from datetime import date, datetime, timedelta
import uuid
import random
import logging
import math
import importlib
import json
import copy
from contextlib import contextmanager
from . import db
from .models import (
    Attendantskills,
    ShiftAssignment,
    Elderdemand,
    DicNursingAction,
    ScheduleResult,
    TimeSlot,
)
from config_params import (
    shift_config,
    day_night_ratio,
    reserve_resource_ratio,
    params,
    shift_control,
    shift_mode_config,
    rest_time_control,
)
from sqlalchemy import func
from .activity_scheduler import ActivityScheduler
from .activity_continuity import ActivityContinuityChecker

# 动态导入算法模块
try:
    # 基础算法模块
    nsga2_module = importlib.import_module("app.nsga2")
    constraint_solver_module = importlib.import_module("app.constraint_solver")
    rl_scheduler_module = importlib.import_module("app.rl_scheduler")

    # 增强版算法模块
    enhanced_nsga2_module = importlib.import_module("app.enhanced_nsga2")
    enhanced_sa_module = importlib.import_module("app.enhanced_sa")
    enhanced_rl_module = importlib.import_module("app.enhanced_rl")

    # 基础算法类
    NSGA2Optimizer = nsga2_module.NSGA2Optimizer
    ConstraintSolver = constraint_solver_module.ConstraintSolver
    RLScheduler = rl_scheduler_module.RLScheduler

    # 增强版算法类
    EnhancedNSGA2Optimizer = enhanced_nsga2_module.EnhancedNSGA2Optimizer
    EnhancedSimulatedAnnealing = enhanced_sa_module.EnhancedSimulatedAnnealing
    EnhancedRLOptimizer = enhanced_rl_module.EnhancedRLOptimizer

    ADVANCED_ALGORITHMS_AVAILABLE = True
except ImportError as e:
    print(f"导入算法模块时出错: {str(e)}")
    ADVANCED_ALGORITHMS_AVAILABLE = False


class ThreeShiftScheduler:
    """三班制排班调度器"""

    def __init__(self):
        """初始化排班调度器"""
        # 基本配置
        self.shift_config = shift_config
        self.day_night_ratio = day_night_ratio
        self.reserve_resource_ratio = reserve_resource_ratio
        self.time_slots_per_day = params["time_slots_per_day"]
        self.time_interval_minutes = params["time_interval_minutes"]

        # 班制控制参数
        self.shift_control = shift_control
        self.shift_mode_config = shift_mode_config
        self.rest_time_control = rest_time_control

        # 初始化当前激活的班制模式
        self.active_mode = "three_shift"  # 默认为三班制
        self.current_shift_times = {}

        # 复用原接口的算法参数
        self.population_size = params.get("population_size", 20)
        self.crossover_rate = params.get("crossover_rate", 0.3)
        self.mutation_rate = params.get("mutation_rate", 0.115)
        self.phenotype_limit = params.get("phenotype_limit", 200)
        self.elimination_size = params.get("elimination_size", 5)

        # 模拟退火算法参数
        self.initial_temperature = params.get(
            "initial_temperature", 100.0
        )  # 使用全局参数中的初始温度
        self.cooling_rate = params.get("cooling_rate", 0.995)  # 使用全局参数中的冷却率
        self.temperature = self.initial_temperature  # 当前温度，用于模拟退火

        # 初始化日志
        self.logger = logging.getLogger(__name__)
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            )
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            self.logger.setLevel(logging.INFO)

        self.logger.info("初始化三班制排班调度器")
        self.logger.info(
            f"算法参数: population_size={self.population_size}, crossover_rate={self.crossover_rate}, "
            f"mutation_rate={self.mutation_rate}, phenotype_limit={self.phenotype_limit}, "
            f"initial_temperature={self.initial_temperature}, cooling_rate={self.cooling_rate}"
        )

        # 计算班次时间
        self.calculate_shift_times()

        # 初始化活动调度器
        self.activity_scheduler = ActivityScheduler(logger=self.logger)
        self.logger.info("活动调度器初始化完成")

        # 初始化活动连续性检查器
        self.continuity_checker = ActivityContinuityChecker()
        self.logger.info("活动连续性检查器初始化完成")

        # 初始化高级算法
        self.init_advanced_algorithms()

    def init_advanced_algorithms(self):
        """初始化高级算法"""
        # 检查高级算法是否可用
        if (
            "ADVANCED_ALGORITHMS_AVAILABLE" in globals()
            and ADVANCED_ALGORITHMS_AVAILABLE
        ):
            self.logger.info("高级算法模块可用，初始化高级算法...")

            # 初始化基础算法
            # 初始化NSGA-II多目标优化算法
            self.nsga2_optimizer = NSGA2Optimizer(
                population_size=self.population_size,
                crossover_rate=self.crossover_rate,
                mutation_rate=self.mutation_rate,
                phenotype_limit=self.phenotype_limit,
                elimination_size=self.elimination_size,
            )

            # 初始化约束满足算法
            self.constraint_solver = ConstraintSolver()

            # 初始化强化学习算法
            self.rl_scheduler = RLScheduler(
                learning_rate=params.get("rl_learning_rate", 0.1),
                discount_factor=params.get("rl_discount_factor", 0.9),
                exploration_rate=params.get("rl_exploration_rate", 0.1),
                exploration_decay=params.get("rl_exploration_decay", 0.995),
                min_exploration_rate=params.get("rl_min_exploration_rate", 0.01),
            )

            # 初始化增强版算法
            # 初始化增强版NSGA-II多目标优化算法
            self.enhanced_nsga2_optimizer = EnhancedNSGA2Optimizer(
                population_size=params.get("enhanced_population_size", 30),
                crossover_rate=params.get("enhanced_crossover_rate", 0.5),
                mutation_rate=params.get("enhanced_mutation_rate", 0.15),
                phenotype_limit=params.get("enhanced_phenotype_limit", 300),
                elimination_size=params.get("enhanced_elimination_size", 5),
                max_no_improvement=params.get("enhanced_max_no_improvement", 50),
                adaptive_rates=params.get("enhanced_adaptive_rates", True),
                elitism=params.get("enhanced_elitism", True),
                local_search=params.get("enhanced_local_search", True),
                parallel_evaluation=params.get("enhanced_parallel_evaluation", True),
                early_stopping=params.get("enhanced_early_stopping", True),
            )

            # 初始化增强版模拟退火算法
            self.enhanced_sa = EnhancedSimulatedAnnealing(
                initial_temperature=params.get("enhanced_initial_temperature", 200.0),
                cooling_rate=params.get("enhanced_cooling_rate", 0.95),
                min_temperature=params.get("enhanced_min_temperature", 0.01),
                max_iterations=params.get("enhanced_max_iterations", 1000),
                max_no_improvement=params.get("enhanced_max_no_improvement", 50),
                restart_temperature=params.get("enhanced_restart_temperature", 500.0),
                restart_threshold=params.get("enhanced_restart_threshold", 0.01),
                memory_size=params.get("enhanced_memory_size", 10),
                num_starts=params.get("enhanced_num_starts", 3),
                local_search_prob=params.get("enhanced_local_search_prob", 0.1),
            )

            # 初始化增强版强化学习算法
            self.enhanced_rl = EnhancedRLOptimizer(
                learning_rate=params.get("enhanced_rl_learning_rate", 0.1),
                discount_factor=params.get("enhanced_rl_discount_factor", 0.9),
                exploration_rate=params.get("enhanced_rl_exploration_rate", 0.3),
                exploration_decay=params.get("enhanced_rl_exploration_decay", 0.995),
                min_exploration_rate=params.get(
                    "enhanced_rl_min_exploration_rate", 0.01
                ),
                max_episodes=params.get("enhanced_rl_max_episodes", 500),
                memory_size=params.get("enhanced_rl_memory_size", 1000),
                batch_size=params.get("enhanced_rl_batch_size", 32),
                update_target_freq=params.get("enhanced_rl_update_target_freq", 10),
                use_double_q=params.get("enhanced_rl_use_double_q", True),
                use_prioritized_replay=params.get(
                    "enhanced_rl_use_prioritized_replay", True
                ),
            )

            self.logger.info("高级算法初始化完成")
        else:
            self.logger.info("高级算法模块不可用，将使用基本算法")

    def parse_time(self, time_str):
        """解析时间字符串为datetime.time对象"""
        return datetime.strptime(time_str, "%H:%M").time()

    def _create_initial_time_slots(self):
        """创建初始的时间段列表，默认为睡眠活动"""
        try:
            initial_slots = []
            for slot_idx in range(self.time_slots_per_day):
                # 计算时间段
                slot_hours = (slot_idx * self.time_interval_minutes) // 60
                slot_minutes = (slot_idx * self.time_interval_minutes) % 60
                end_hours = ((slot_idx + 1) * self.time_interval_minutes) // 60
                end_minutes = ((slot_idx + 1) * self.time_interval_minutes) % 60

                # 处理跨天的情况
                is_overnight = False
                if end_hours >= 24:
                    is_overnight = True
                    display_end_hours = end_hours - 24
                else:
                    display_end_hours = end_hours

                # 如果是跨天，添加标记
                time_slot_str = f"{slot_hours:02d}:{slot_minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}"
                if is_overnight:
                    # 在日志中添加跨天标记，但不改变时间格式
                    self.logger.debug(f"创建跨天时间段: {time_slot_str} (跨天)")

                # 使用活动调度器确定默认活动
                # 检查是否是睡眠时间
                is_sleep_time = self.activity_scheduler.is_fixed_time_activity(
                    10, time_slot_str
                )

                if is_sleep_time:
                    # 如果是睡眠时间，默认为睡眠活动
                    entry = self.create_schedule_entry(
                        time_str=time_slot_str,
                        activity_name="睡眠",
                        activity_id="10",
                        caregiver_name="None",
                        caregiver_id="0",
                    )
                else:
                    # 如果不是睡眠时间，默认为日常生活活动
                    entry = self.create_schedule_entry(
                        time_str=time_slot_str,
                        activity_name="日常生活",
                        activity_id="8",
                        caregiver_name="None",
                        caregiver_id="0",
                    )
                initial_slots.append(entry)

            self.logger.debug(f"创建了 {len(initial_slots)} 个初始时间段条目")
            return initial_slots
        except Exception as e:
            self.logger.error(f"创建初始时间段失败: {str(e)}")
            # 返回一个空列表，避免程序崩溃
            return []

    def _validate_and_fix_schedule_data(self, schedule_entries):
        """验证和修复排班数据，确保数据类型一致性和格式统一

        Args:
            schedule_entries: 排班数据，可能是列表、字典或字符串

        Returns:
            验证和修复后的排班数据，始终是列表类型，包含self.time_slots_per_day个条目
            每个条目都是字典，包含TimeSlot、Activity、ActivityId、Caregiver、CaregiverId字段
        """
        try:
            # 如果是字符串，尝试解析为JSON
            if isinstance(schedule_entries, str):
                self.logger.warning("排班数据是字符串类型，尝试解析为JSON")
                import json

                try:
                    schedule_entries = json.loads(schedule_entries)
                except json.JSONDecodeError:
                    self.logger.error(
                        f"无法解析排班数据为JSON: {schedule_entries[:100]}..."
                    )
                    return self._create_initial_time_slots()

            # 确保是列表类型
            if not isinstance(schedule_entries, list):
                self.logger.warning("排班数据不是列表类型，转换为列表")
                if isinstance(schedule_entries, dict):
                    # 如果是字典，可能是单个条目，将其放入列表
                    schedule_entries = [schedule_entries] if schedule_entries else []
                else:
                    # 如果是其他类型，创建新的默认条目列表
                    self.logger.warning(
                        f"排班数据类型不支持: {type(schedule_entries)}，创建新的默认条目列表"
                    )
                    return self._create_initial_time_slots()

            # 创建一个新的列表，用于存储验证和修复后的条目
            validated_entries = [None] * self.time_slots_per_day

            # 创建一个时间段字典，用于检查重复的时间段
            time_slot_dict = {}

            # 记录处理的条目数量
            processed_count = 0

            # 处理每个条目
            for entry in schedule_entries:
                if not isinstance(entry, dict):
                    self.logger.warning(f"跳过非字典类型的条目: {entry}")
                    continue  # 跳过非字典类型的条目

                # 确保必要的字段存在
                if "TimeSlot" not in entry:
                    self.logger.warning(f"跳过没有TimeSlot字段的条目: {entry}")
                    continue  # 跳过没有TimeSlot字段的条目

                processed_count += 1

                # 尝试解析时间段，获取索引
                try:
                    time_slot = entry["TimeSlot"]
                    if "-" not in time_slot:
                        continue  # 跳过格式不正确的时间段

                    time_parts = time_slot.split("-")
                    if len(time_parts) != 2:
                        continue  # 跳过格式不正确的时间段

                    start_time = time_parts[0]
                    # end_time = time_parts[1]  # 暂时不需要使用结束时间

                    if ":" not in start_time:
                        continue  # 跳过格式不正确的开始时间

                    time_components = start_time.split(":")
                    if len(time_components) != 2:
                        continue  # 跳过格式不正确的开始时间

                    try:
                        hours = int(time_components[0])
                        minutes = int(time_components[1])
                    except ValueError:
                        continue  # 跳过无法转换为整数的时间

                    # 计算时间段索引
                    time_index = hours * (60 // self.time_interval_minutes) + (
                        minutes // self.time_interval_minutes
                    )

                    # 确保索引在有效范围内
                    if 0 <= time_index < self.time_slots_per_day:
                        # 如果该时间段已经有条目，跳过
                        if time_index in time_slot_dict:
                            continue

                        # 确保所有必要的字段都存在
                        validated_entry = {
                            "TimeSlot": time_slot,
                            "Activity": entry.get("Activity", "睡眠"),
                            "ActivityId": entry.get("ActivityId", "10"),
                            "Caregiver": entry.get("Caregiver", "None"),
                            "CaregiverId": entry.get("CaregiverId", "0"),
                        }

                        # 添加到验证后的列表
                        validated_entries[time_index] = validated_entry
                        time_slot_dict[time_index] = True
                        self.logger.debug(
                            f"添加时间段条目: {time_slot} -> 索引 {time_index}"
                        )
                except Exception as e:
                    self.logger.warning(
                        f"解析时间段失败: {entry.get('TimeSlot', 'Unknown')}, 错误: {str(e)}"
                    )
                    continue

            self.logger.info(
                f"处理了 {processed_count} 个条目，有效条目 {len(time_slot_dict)} 个"
            )

            # 填充空缺的时间段
            empty_slots = 0
            for i in range(self.time_slots_per_day):
                if validated_entries[i] is None:
                    empty_slots += 1
                    # 计算时间段
                    hours = (i * self.time_interval_minutes) // 60
                    minutes = (i * self.time_interval_minutes) % 60
                    end_hours = ((i + 1) * self.time_interval_minutes) // 60
                    end_minutes = ((i + 1) * self.time_interval_minutes) % 60

                    # 处理跨天的情况
                    is_overnight = False
                    if end_hours >= 24:
                        is_overnight = True
                        display_end_hours = end_hours - 24
                    else:
                        display_end_hours = end_hours

                    time_slot_str = f"{hours:02d}:{minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}"
                    if is_overnight:
                        self.logger.debug(f"创建跨天时间段: {time_slot_str} (跨天)")

                    # 使用活动调度器确定默认活动
                    # 检查是否是睡眠时间
                    is_sleep_time = (
                        self.activity_scheduler.is_fixed_time_activity(
                            10, time_slot_str
                        )
                        if hasattr(self, "activity_scheduler")
                        else True
                    )

                    if is_sleep_time:
                        # 如果是睡眠时间，默认为睡眠活动
                        activity_name = "睡眠"
                        activity_id = "10"
                    else:
                        # 如果不是睡眠时间，默认为日常生活活动
                        activity_name = "日常生活"
                        activity_id = "8"

                    validated_entries[i] = {
                        "TimeSlot": time_slot_str,
                        "Activity": activity_name,
                        "ActivityId": activity_id,
                        "Caregiver": "None",
                        "CaregiverId": "0",
                    }

            self.logger.info(f"填充了 {empty_slots} 个空缺时间段")

            # 确保所有时间段都有条目
            if not (len(validated_entries) == self.time_slots_per_day):
                raise ValueError(f"验证后的条目数量 {len(validated_entries)} 不等于时间段数量 {self.time_slots_per_day}")
            if not all(entry is not None for entry in validated_entries):
                raise ValueError("验证后的条目列表中有None元素")

            # 按时间排序
            validated_entries.sort(key=lambda x: x["TimeSlot"])

            # 确保字段顺序一致，与原接口保持一致
            standardized_entries = []
            for entry in validated_entries:
                standardized_entry = {
                    "TimeSlot": entry["TimeSlot"],
                    "Activity": entry["Activity"],
                    "ActivityId": entry["ActivityId"],
                    "Caregiver": entry["Caregiver"],
                    "CaregiverId": entry["CaregiverId"],
                }
                standardized_entries.append(standardized_entry)

            # 记录日志
            self.logger.info(
                f"验证和修复排班数据完成，共 {len(standardized_entries)} 个条目"
            )

            return standardized_entries
        except Exception as e:
            self.logger.error(f"验证和修复排班数据时出错: {str(e)}")
            import traceback

            self.logger.error(traceback.format_exc())
            # 如果出错，创建新的默认条目列表
            return self._create_initial_time_slots()

    def create_schedule_entry(
        self, time_str, activity_name, activity_id, caregiver_name, caregiver_id
    ):
        """创建时间表条目，与原接口格式保持一致

        增强版本：
        1. 增强活动名称处理，确保活动名称正确
        2. 处理特殊情况，如活动ID为10时强制设置为睡眠

        Args:
            time_str: 时间字符串，格式为'HH:MM'或'HH:MM-HH:MM'
            activity_name: 活动名称
            activity_id: 活动ID
            caregiver_name: 护理员姓名
            caregiver_id: 护理员ID

        Returns:
            包含时间段信息的字典
        """
        try:
            # 处理特殊情况
            # 如果活动ID为10，强制设置活动名称为睡眠
            if activity_id == "10" or activity_id == 10:
                activity_name = "睡眠"
            # 如果活动ID为8，强制设置活动名称为日常生活
            elif activity_id == "8" or activity_id == 8:
                activity_name = "日常生活"
            # 如果活动名称为未知活动，尝试从数据库获取活动名称
            elif activity_name == "未知活动" and activity_id:
                # 获取护理动作详情
                nursing_actions = self.get_nursing_actions()

                # 尝试不同的格式获取活动
                action = None
                if activity_id in nursing_actions:
                    action = nursing_actions[activity_id]
                elif str(activity_id) in nursing_actions:
                    action = nursing_actions[str(activity_id)]

                # 如果找到了活动，使用其名称
                if action and hasattr(action, "name") and action.name:
                    activity_name = action.name
                else:
                    # 如果仍然找不到活动名称，使用活动ID作为名称
                    activity_name = f"活动{activity_id}"

            # 解析时间字符串
            if "-" in time_str:
                # 如果已经是完整的时间段格式，直接使用
                time_slot = time_str
            else:
                # 如果只是开始时间，计算结束时间
                hours, minutes = map(int, time_str.split(":"))

                # 计算结束时间（根据配置的时间间隔）
                end_minutes = minutes + self.time_interval_minutes
                end_hours = hours
                if end_minutes >= 60:
                    end_minutes -= 60
                    end_hours += 1
                # 处理跨天的情况
                is_overnight = False
                if end_hours >= 24:
                    is_overnight = True
                    display_end_hours = end_hours - 24
                else:
                    display_end_hours = end_hours

                # 记录日志
                log_message = f"创建时间段: {hours:02d}:{minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}, 间隔: {self.time_interval_minutes} 分钟"
                if is_overnight:
                    log_message += " (跨天)"
                self.logger.debug(log_message)

                # 格式化时间段字符串
                time_slot = f"{hours:02d}:{minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}"

            # 创建与原接口格式一致的条目
            return {
                "TimeSlot": time_slot,
                "Activity": activity_name,
                "ActivityId": str(activity_id),  # 确保活动ID是字符串格式
                "Caregiver": caregiver_name,
                "CaregiverId": str(caregiver_id),  # 确保护理员ID是字符串格式
            }
        except Exception as e:
            self.logger.error(f"创建时间段条目失败: {str(e)}")
            # 返回一个默认的条目，避免程序崩溃
            return {
                "TimeSlot": "00:00-00:30",
                "Activity": "睡眠",
                "ActivityId": "10",
                "Caregiver": "None",
                "CaregiverId": "0",
            }

    def calculate_shift_times(self):
        """根据当前配置计算每个班次的实际时间"""
        # 获取当前激活的班制模式
        active_mode = self.active_mode

        # 确定要使用的班次列表
        if active_mode == "custom":
            if hasattr(self, "custom_shifts") and self.custom_shifts:
                active_shifts = self.custom_shifts
            else:
                active_shifts = self.shift_mode_config["three_shift"][
                    "shifts"
                ]  # 默认使用三班制
        else:
            active_shifts = self.shift_mode_config[active_mode]["shifts"]

        # 过滤启用的班次
        enabled_shifts = [
            shift
            for shift in active_shifts
            if shift in self.shift_control["enabled_shifts"]
        ]

        # 如果没有启用的班次，使用默认的三班制
        if not enabled_shifts:
            self.logger.warning("没有启用的班次，使用默认的三班制")
            enabled_shifts = self.shift_mode_config["three_shift"]["shifts"]

        # 计算每个班次的时长
        total_shifts = len(enabled_shifts)
        if total_shifts == 0:
            self.logger.warning("没有激活的班次，无法计算班次时间")
            return {}

        # 根据班制模式确定每个班次的时长
        if self.shift_control["auto_adjust_time"]:
            # 如果自动调整时间，则平均分配24小时
            if (
                active_mode in self.shift_mode_config
                and "hours_per_shift" in self.shift_mode_config[active_mode]
                and self.shift_mode_config[active_mode]["hours_per_shift"] is not None
            ):
                # 使用班制模式配置中的时长
                hours_per_shift = self.shift_mode_config[active_mode]["hours_per_shift"]
                hours_per_shift_list = [hours_per_shift] * total_shifts
                self.logger.info(
                    f"使用{self.shift_mode_config[active_mode]['name']}配置的时长，每个班次 {hours_per_shift} 小时"
                )
            else:
                # 平均分配24小时
                hours_per_shift = 24 / total_shifts
                hours_per_shift_list = [hours_per_shift] * total_shifts
                self.logger.info(f"自动调整时间，每个班次 {hours_per_shift} 小时")
        else:
            # 否则使用默认时长
            hours_per_shift = 8  # 默认每班8小时
            hours_per_shift_list = [hours_per_shift] * total_shifts
            self.logger.info(f"使用默认时长，每个班次 {hours_per_shift} 小时")

        # 计算每个班次的开始和结束时间
        start_time_str = self.shift_config[enabled_shifts[0]]["start_time"]
        start_time = datetime.strptime(start_time_str, "%H:%M")

        shift_times = {}
        current_time = start_time

        for i, shift in enumerate(enabled_shifts):
            shift_start = current_time.strftime("%H:%M")

            # 计算结束时间，使用对应的班次时长
            hours_per_shift = (
                hours_per_shift_list[i]
                if i < len(hours_per_shift_list)
                else hours_per_shift_list[-1]
            )
            current_time = current_time + timedelta(hours=hours_per_shift)
            shift_end = current_time.strftime("%H:%M")

            shift_times[shift] = {
                "start_time": shift_start,
                "end_time": shift_end,
                "duration": hours_per_shift,
                "enabled": True,  # 默认启用
            }

        self.current_shift_times = shift_times
        self.logger.info(f"计算班次时间: {shift_times}")
        return shift_times

    def set_shift_mode(self, mode, custom_shifts=None, start_time=None):
        """设置班制模式

        Args:
            mode: 班制模式名称，可以是字符串('one_shift', 'two_shift', 'three_shift', 'custom')
                  或者数字(1, 2, 3)，分别表示一班制、二班制、三班制
            custom_shifts: 自定义模式下的班次列表
            start_time: 第一个班次的开始时间
        """
        # 记录原始班制模式
        original_mode = self.active_mode
        self.logger.info(f"原始班制模式: {original_mode}")

        # 处理数字班制参数
        if isinstance(mode, int) or (isinstance(mode, str) and mode.isdigit()):
            # 将数字转换为整数
            shift_number = int(mode)
            # 根据数字映射到班制模式
            if shift_number == 1:
                mode = "one_shift"
                self.logger.info(f"数字班制参数 {shift_number} 映射到一班制")
            elif shift_number == 2:
                mode = "two_shift"
                self.logger.info(f"数字班制参数 {shift_number} 映射到二班制")
            elif shift_number == 3:
                mode = "three_shift"
                self.logger.info(f"数字班制参数 {shift_number} 映射到三班制")
            elif shift_number == 4:
                mode = "custom"
                self.logger.info(f"数字班制参数 {shift_number} 映射到自定义班制")
            else:
                self.logger.warning(
                    f"无效的数字班制参数: {shift_number}，使用默认的三班制"
                )
                mode = "three_shift"

        # 检查班制模式是否有效
        if mode not in self.shift_mode_config:
            self.logger.warning(f"无效的班制模式: {mode}，使用默认的三班制")
            mode = "three_shift"

        # 更新激活模式
        self.active_mode = mode
        self.logger.info(f"设置班制模式为: {mode}")

        # 根据班制模式更新启用的班次
        if mode in self.shift_mode_config and mode != "custom":
            # 使用配置文件中定义的班次
            self.shift_control["enabled_shifts"] = self.shift_mode_config[mode][
                "shifts"
            ]
            self.logger.info(
                f"{self.shift_mode_config[mode]['name']}模式，启用班次: {self.shift_control['enabled_shifts']}"
            )
        elif mode == "custom":
            # 自定义模式
            if custom_shifts:
                # 处理数字班次
                if isinstance(custom_shifts, list) and all(
                    isinstance(item, int) or (isinstance(item, str) and item.isdigit())
                    for item in custom_shifts
                ):
                    # 将数字班次转换为班次标识符
                    number_to_shift = {
                        1: "morning_shift",
                        2: "afternoon_shift",
                        3: "night_shift",
                    }

                    shift_list = []
                    for number in custom_shifts:
                        number = int(number)
                        if number in number_to_shift:
                            shift_list.append(number_to_shift[number])
                        else:
                            self.logger.warning(f"无效的班次编号: {number}，已跳过")

                    self.logger.info(
                        f"将数字班次 {custom_shifts} 转换为班次标识符: {shift_list}"
                    )
                    custom_shifts = shift_list

                # 验证自定义班次
                valid_shifts = []
                for shift in custom_shifts:
                    if shift in self.shift_config:
                        valid_shifts.append(shift)
                    else:
                        self.logger.warning(f"无效的班次: {shift}，已跳过")

                if valid_shifts:
                    self.shift_control["enabled_shifts"] = valid_shifts
                    self.custom_shifts = valid_shifts
                    self.logger.info(f"自定义模式，启用班次: {valid_shifts}")
                else:
                    self.logger.warning("没有有效的自定义班次，使用默认的三班制")
                    self.shift_control["enabled_shifts"] = self.shift_mode_config[
                        "three_shift"
                    ]["shifts"]
                    self.logger.info(
                        f"回退到三班制模式，启用班次: {self.shift_control['enabled_shifts']}"
                    )
            else:
                # 如果没有提供自定义班次，尝试从全局参数中获取
                from config_params import three_shift_params

                global_custom_shifts = three_shift_params.get("custom_shifts")

                if global_custom_shifts:
                    self.logger.info(
                        f"使用全局参数中的自定义班次: {global_custom_shifts}"
                    )
                    # 递归调用自己，处理全局自定义班次
                    return self.set_shift_mode(mode, global_custom_shifts, start_time)
                else:
                    self.logger.warning(
                        "自定义模式下没有提供班次列表，使用默认的三班制"
                    )
                    self.shift_control["enabled_shifts"] = self.shift_mode_config[
                        "three_shift"
                    ]["shifts"]
                    self.logger.info(
                        f"回退到三班制模式，启用班次: {self.shift_control['enabled_shifts']}"
                    )
        else:
            # 如果模式无效，使用默认的三班制
            self.logger.warning(f"无法识别的班制模式: {mode}，使用默认的三班制")
            self.shift_control["enabled_shifts"] = self.shift_mode_config[
                "three_shift"
            ]["shifts"]
            self.logger.info(
                f"回退到三班制模式，启用班次: {self.shift_control['enabled_shifts']}"
            )

        # 如果提供了开始时间，更新第一个班次的开始时间
        if start_time:
            try:
                # 验证时间格式
                datetime.strptime(start_time, "%H:%M")

                # 获取第一个启用的班次
                if self.shift_control["enabled_shifts"]:
                    first_shift = self.shift_control["enabled_shifts"][0]
                    self.shift_config[first_shift]["start_time"] = start_time
                    self.logger.info(
                        f"设置第一个班次 {first_shift} 的开始时间为: {start_time}"
                    )
            except ValueError:
                self.logger.error(f"无效的时间格式: {start_time}，请使用HH:MM格式")

        # 重新计算班次时间
        self.calculate_shift_times()
        self.logger.info(f"班制模式设置完成，班次时间: {self.current_shift_times}")

        # 检查班制模式是否有变化
        if original_mode != self.active_mode:
            self.logger.info(f"班制模式已从 {original_mode} 变更为 {self.active_mode}")

        return {
            "mode": self.active_mode,
            "name": self.shift_mode_config[self.active_mode]["name"],
            "enabled_shifts": self.shift_control["enabled_shifts"],
            "shift_times": self.current_shift_times,
        }

    def update_shift_config(self, enabled_shifts=None):
        """更新班次配置

        Args:
            enabled_shifts: 启用的班次列表，例如 ['morning_shift', 'afternoon_shift']
        """
        if enabled_shifts is not None:
            # 验证班次名称
            valid_shifts = set(self.shift_config.keys())
            for shift in enabled_shifts:
                if shift not in valid_shifts:
                    raise ValueError(f"无效的班次名称: {shift}")

            # 更新启用的班次
            self.shift_control["enabled_shifts"] = enabled_shifts

            # 重新计算班次时间
            self.calculate_shift_times()

            self.logger.info(f"更新班次配置: {self.shift_control}")

    def update_shift_control(
        self,
        allow_empty_shifts=None,
        min_shifts=None,
        max_shifts=None,
        auto_adjust_time=None,
    ):
        """更新班次控制参数

        Args:
            allow_empty_shifts: 是否允许空班次
            min_shifts: 最小班次数
            max_shifts: 最大班次数
            auto_adjust_time: 是否自动调整班次时间
        """
        if allow_empty_shifts is not None:
            self.shift_control["allow_empty_shifts"] = allow_empty_shifts

        if min_shifts is not None:
            self.shift_control["min_shifts_per_day"] = min_shifts

        if max_shifts is not None:
            self.shift_control["max_shifts_per_day"] = max_shifts

        if auto_adjust_time is not None:
            self.shift_control["auto_adjust_time"] = auto_adjust_time
            # 如果更改了自动调整时间设置，重新计算班次时间
            self.calculate_shift_times()

        self.logger.info(f"更新班次控制参数: {self.shift_control}")

    def disable_shifts(self, shifts_to_disable):
        """临时禁用特定班次（不排班但保留时间段）

        Args:
            shifts_to_disable: 要禁用的班次列表
        """
        # 验证班次名称
        active_shifts = list(self.current_shift_times.keys())

        for shift in shifts_to_disable:
            if shift not in active_shifts:
                self.logger.warning(f"班次 {shift} 不在当前激活的班次列表中")

        # 更新班次启用状态
        for shift in self.current_shift_times:
            self.current_shift_times[shift]["enabled"] = shift not in shifts_to_disable

        self.logger.info(
            f"禁用班次: {shifts_to_disable}, 更新后的班次时间: {self.current_shift_times}"
        )

    def calculate_shift_hours(self, shift_type):
        """计算班次的工作时长（小时）

        Args:
            shift_type: 班次类型

        Returns:
            float: 工作时长（小时）
        """
        # 如果班次在当前计算的时间中
        if shift_type in self.current_shift_times:
            return self.current_shift_times[shift_type]["duration"]

        # 否则使用原始配置计算
        if shift_type not in self.shift_config:
            self.logger.warning(f"未知的班次类型: {shift_type}")
            return 8  # 默认返8小时

        start_time = self.parse_time(self.shift_config[shift_type]["start_time"])
        end_time = self.parse_time(self.shift_config[shift_type]["end_time"])

        # 处理跨天情况
        if end_time < start_time:
            hours = (24 - start_time.hour - start_time.minute / 60) + (
                end_time.hour + end_time.minute / 60
            )
        else:
            hours = (end_time.hour - start_time.hour) + (
                end_time.minute - start_time.minute
            ) / 60

        return hours

    def check_rest_time_constraints(self, caregiver_id, target_date, target_shift):
        """检查护理员的休息时间约束

        Args:
            caregiver_id: 护理员ID
            target_date: 目标排班日期
            target_shift: 目标班次

        Returns:
            bool: 是否满足休息时间约束
        """
        # 获取护理员最近的排班记录
        recent_assignments = (
            ShiftAssignment.query.filter(
                ShiftAssignment.caregiver_id == caregiver_id,
                ShiftAssignment.shift_date < target_date,
                ShiftAssignment.shift_date
                >= target_date - timedelta(days=7),  # 查看过去7天
            )
            .order_by(ShiftAssignment.shift_date.desc())
            .all()
        )

        if not recent_assignments:
            # 没有最近的排班记录，可以安排任何班次
            return True

        # 获取最近一次的排班
        last_assignment = recent_assignments[0]
        last_shift = last_assignment.shift_type
        last_date = last_assignment.shift_date
        last_end_time = last_assignment.shift_end_time

        # 计算两个班次之间的时间间隔（小时）
        if target_shift not in self.current_shift_times:
            self.logger.warning(f"目标班次 {target_shift} 不在当前班次时间中")
            return True  # 如果目标班次不在当前班次时间中，允许安排

        target_start_time_str = self.current_shift_times[target_shift]["start_time"]
        target_start_time = self.parse_time(target_start_time_str)
        target_start_datetime = datetime.combine(target_date, target_start_time)

        last_end_datetime = datetime.combine(last_date, last_end_time)

        # 处理跨天情况
        if last_end_time < self.parse_time("06:00"):
            last_end_datetime = datetime.combine(
                last_date + timedelta(days=1), last_end_time
            )

        hours_between = (
            target_start_datetime - last_end_datetime
        ).total_seconds() / 3600

        # 检查基本休息时间
        min_rest = self.rest_time_control["min_rest_between_shifts"]

        # 如果上一个班次是夜班，需要更长的休息时间
        if last_shift == "班次3" or last_shift == "night_shift":
            min_rest = self.rest_time_control["min_rest_after_night_shift"]

        # 检查班次转换休息时间
        # 将班次名称映射到内部名称
        shift_name_map = {
            "班次1": "morning_shift",
            "班次2": "afternoon_shift",
            "班次3": "night_shift",
        }

        last_shift_internal = shift_name_map.get(last_shift, last_shift)
        target_shift_internal = shift_name_map.get(target_shift, target_shift)

        transition_key = f"{last_shift_internal}_to_{target_shift_internal}"
        if transition_key in self.rest_time_control["shift_transition_rest"]:
            transition_rest = self.rest_time_control["shift_transition_rest"][
                transition_key
            ]
            min_rest = max(min_rest, transition_rest)

        # 检查是否满足最小休息时间要求
        if hours_between < min_rest:
            self.logger.info(
                f"护理员 {caregiver_id} 不满足休息时间要求: 需要 {min_rest} 小时，实际 {hours_between:.2f} 小时"
            )
            return False

        # 检查连续工作班次数
        consecutive_shifts = 1  # 从最近的一个班次开始计数
        current_date = last_date
        for assignment in recent_assignments[1:]:
            if (current_date - assignment.shift_date).days <= 1:  # 连续的日期
                consecutive_shifts += 1
                current_date = assignment.shift_date
            else:
                break

        if consecutive_shifts >= self.rest_time_control["max_consecutive_shifts"]:
            self.logger.info(
                f"护理员 {caregiver_id} 已经连续工作 {consecutive_shifts} 个班次，超过最大限制"
            )
            return False

        # 检查每周工作时间
        weekly_work_hours = 0
        for assignment in recent_assignments:
            # 计算班次工作时长
            shift_hours = self.calculate_shift_hours(assignment.shift_type)
            weekly_work_hours += shift_hours

        # 加上目标班次的工作时长
        target_shift_hours = self.calculate_shift_hours(target_shift)
        if (
            weekly_work_hours + target_shift_hours
            > self.rest_time_control["max_weekly_work_hours"]
        ):
            self.logger.info(
                f"护理员 {caregiver_id} 每周工作时间将超过限制: {weekly_work_hours + target_shift_hours} > {self.rest_time_control['max_weekly_work_hours']}"
            )
            return False

        # 检查每周夜班次数
        if target_shift == "班次3" or target_shift == "night_shift":
            weekly_night_shifts = sum(
                1
                for a in recent_assignments
                if a.shift_type == "班次3" or a.shift_type == "night_shift"
            )
            if (
                weekly_night_shifts + 1
                > self.rest_time_control["max_weekly_night_shifts"]
            ):
                self.logger.info(
                    f"护理员 {caregiver_id} 每周夜班次数将超过限制: {weekly_night_shifts + 1} > {self.rest_time_control['max_weekly_night_shifts']}"
                )
                return False

        # 检查周末休息要求
        if self.rest_time_control["require_weekend_rest"]:
            target_weekday = target_date.weekday()
            if target_weekday >= 5:  # 5=周六，6=周日
                # 检查本月已经安排的周末班次数
                month_start = target_date.replace(day=1)
                next_month = target_date.replace(day=28) + timedelta(days=4)
                month_end = next_month.replace(day=1) - timedelta(days=1)

                weekend_shifts = ShiftAssignment.query.filter(
                    ShiftAssignment.caregiver_id == caregiver_id,
                    ShiftAssignment.shift_date >= month_start,
                    ShiftAssignment.shift_date <= month_end,
                    func.extract("dow", ShiftAssignment.shift_date).in_(
                        [5, 6]
                    ),  # 周六和周日
                ).count()

                if (
                    weekend_shifts
                    >= self.rest_time_control["max_weekend_shifts_per_month"]
                ):
                    self.logger.info(
                        f"护理员 {caregiver_id} 本月周末班次数将超过限制: {weekend_shifts + 1} > {self.rest_time_control['max_weekend_shifts_per_month']}"
                    )
                    return False

        return True

    def get_caregivers(self):
        """获取护理员信息，限制数量"""
        from config_params import params

        all_caregivers = Attendantskills.query.all()

        # 使用与原程序相同的参数限制数量
        limit = params.get("caregiver_num", len(all_caregivers))
        caregivers = all_caregivers[:limit]

        self.logger.info(
            f"从数据库中获取到 {len(all_caregivers)} 个护理员，使用 {len(caregivers)} 个"
        )
        return caregivers

    def evaluate_care_needs(self, elder_id):
        """评估老人的照护需求级别

        基于老人的护理动作需求，评估老人的照护需求级别。
        照护需求级别分为：
        - 高级别（3）：需要专业护理技能的老人，如需要特殊医疗照护
        - 中级别（2）：需要一般护理技能的老人，如需要日常生活辅助
        - 低级别（1）：基本自理能力较好的老人，主要需要陪伴和简单照料

        Args:
            elder_id: 老人ID

        Returns:
            照护需求级别（1-3），数字越大表示需求级别越高
        """
        # 获取老人的护理动作需求
        elder_demands = Elderdemand.query.filter_by(elder=elder_id, arrange="1").all()
        if not elder_demands:
            self.logger.warning(f"老人 {elder_id} 没有护理动作需求记录")
            return 1  # 默认为低级别

        # 解析老人的护理动作需求
        action_ids = []
        for demand in elder_demands:
            if demand.actions:
                action_ids.extend(
                    [
                        int(action_id.strip())
                        for action_id in demand.actions.split(",")
                        if action_id.strip().isdigit()
                    ]
                )

        if not action_ids:
            self.logger.warning(f"老人 {elder_id} 的护理动作需求为空")
            return 1  # 默认为低级别

        # 获取护理动作详情
        actions = DicNursingAction.query.filter(
            DicNursingAction.id.in_(action_ids)
        ).all()
        if not actions:
            self.logger.warning(
                f"老人 {elder_id} 的护理动作 {action_ids} 在数据库中不存在"
            )
            return 1  # 默认为低级别

        # 分析护理动作的级别分布
        level_counts = {}
        for action in actions:
            level = action.level or "0"  # 如果级别为空，则默认为0
            if level not in level_counts:
                level_counts[level] = 0
            level_counts[level] += 1

        # 计算护理动作的平均级别
        total_level = 0
        total_count = 0
        for level, count in level_counts.items():
            try:
                level_value = int(level)
                total_level += level_value * count
                total_count += count
            except ValueError:
                self.logger.warning(f"护理动作级别 {level} 不是有效的数字")

        if total_count == 0:
            self.logger.warning(f"老人 {elder_id} 的护理动作没有有效的级别")
            return 1  # 默认为低级别

        average_level = total_level / total_count

        # 根据平均级别确定照护需求级别
        if average_level >= 4:  # 大部分护理动作是4级或以上
            care_level = 3  # 高级别
        elif average_level >= 3:  # 大部分护理动作是3级或以上
            care_level = 2  # 中级别
        else:  # 大部分护理动作是2级或以下
            care_level = 1  # 低级别

        # 特殊情况处理：如果有特定的高级别护理动作，直接提升到高级别
        high_level_actions = [
            69,
            85,
            86,
            87,
            88,
            89,
            90,
        ]  # 示例：特定的高级别护理动作ID
        if any(action_id in high_level_actions for action_id in action_ids):
            care_level = 3  # 高级别

        self.logger.info(
            f"老人 {elder_id} 的照护需求级别为 {care_level}，平均护理动作级别为 {average_level:.2f}"
        )
        return care_level

    def get_elders(self):
        """获取需要安排照护的老人信息，限制数量"""
        from config_params import params

        all_elders = Elderdemand.query.filter_by(arrange="1").all()

        # 使用与原程序相同的参数限制数量
        limit = params.get("client_num", len(all_elders))

        # 按照老人编号分组，确保获取不同的老人
        distinct_elders = {}
        for elder in all_elders:
            if elder.elder not in distinct_elders:
                distinct_elders[elder.elder] = elder

        # 将不同的老人转换为列表
        distinct_elders_list = list(distinct_elders.values())

        # 限制老人数量
        elders = distinct_elders_list[:limit]

        self.logger.info(
            f"从数据库中获取到 {len(all_elders)} 个需要安排的老人，{len(distinct_elders)} 个不同老人，使用 {len(elders)} 个"
        )
        return elders

    def get_nursing_actions(self):
        """获取所有护理动作信息

        改进版本：
        1. 使用缓存避免重复查询数据库
        2. 同时支持整数和字符串形式的活动ID
        3. 添加默认活动，确保关键活动始终存在
        """
        # 如果已经缓存了护理动作，直接返回
        if hasattr(self, "_nursing_actions_cache"):
            return self._nursing_actions_cache

        # 从数据库获取所有护理动作
        actions = DicNursingAction.query.all()

        # 创建两个字典，分别用于整数ID和字符串ID的查询
        actions_dict_int = {}
        actions_dict_str = {}

        for action in actions:
            # 同时支持整数和字符串形式的ID
            actions_dict_int[action.id] = action
            actions_dict_str[str(action.id)] = action

        # 确保关键活动存在
        # 睡眠活动（ID为10）
        if 10 not in actions_dict_int:
            sleep_action = DicNursingAction(id=10, name="睡眠", level=1)
            actions_dict_int[10] = sleep_action
            actions_dict_str["10"] = sleep_action
            self.logger.warning("数据库中没有睡眠活动（ID=10），已创建默认睡眠活动")

        # 日常生活活动（ID为8）
        if 8 not in actions_dict_int:
            daily_action = DicNursingAction(id=8, name="日常生活", level=1)
            actions_dict_int[8] = daily_action
            actions_dict_str["8"] = daily_action
            self.logger.warning(
                "数据库中没有日常生活活动（ID=8），已创建默认日常生活活动"
            )

        # 合并两个字典，优先使用整数ID
        merged_dict = {**actions_dict_str, **actions_dict_int}

        # 缓存结果
        self._nursing_actions_cache = merged_dict

        self.logger.info(
            f"从数据库中获取到 {len(actions)} 个护理动作，添加了 {len(merged_dict) - len(actions)} 个默认活动"
        )
        return merged_dict

    def parse_skills(self, skills_str):
        """解析技能字符串为技能ID列表"""
        if not skills_str:
            return []
        try:
            return [
                int(skill.strip()) for skill in skills_str.split(",") if skill.strip()
            ]
        except ValueError as e:
            self.logger.error(f"解析技能字符串失败: {skills_str}, 错误: {str(e)}")
            return []

    def get_shift_hours(self, shift_type):
        """计算班次的工作时长（小时）

        Args:
            shift_type: 班次类型

        Returns:
            float: 工作时长（小时），如果班次不存在则返回0
        """
        # 检查班次是否在当前启用的班次中
        if shift_type not in self.shift_control["enabled_shifts"]:
            self.logger.debug(f"班次 {shift_type} 不在当前启用的班次中，返回0小时")
            return 0

        # 使用calculate_shift_hours方法计算工作时长
        return self.calculate_shift_hours(shift_type)

    def calculate_required_caregivers(self, total_caregivers):
        """计算每个班次所需的护理员数量

        改进的算法，确保：
        1. 每个班次都至少有一个护理员（即使总人数很少）
        2. 允许护理员轮班，同一个护理员可以在同一天内担任多个班次
        3. 保留预留资源的概念，但不影响基本的班次覆盖
        """
        # 获取当前启用的班次
        active_shifts = self.shift_control["enabled_shifts"]
        self.logger.info(f"当前启用的班次: {active_shifts}")

        # 初始化结果字典，默认每个班次都不需要护理员
        # 只为启用的班次初始化
        result = {}
        for shift in active_shifts:
            result[shift] = 0  # 默认为0

        self.logger.info(f"初始化班次分配结果字典: {result}")

        # 计算各班次工作时长，只计算启用的班次
        shift_hours = {}
        total_hours = 0
        for shift in active_shifts:
            hours = self.get_shift_hours(shift)
            shift_hours[shift] = hours
            total_hours += hours
            self.logger.info(
                f"{self.shift_config[shift]['name']}工作时长: {hours} 小时"
            )

        # 计算各班次所需人数（考虑预留资源）
        available_caregivers = max(
            1, int(total_caregivers * (1 - self.reserve_resource_ratio))
        )
        self.logger.info(
            f"总护理员数量: {total_caregivers}, 可用护理员数量: {available_caregivers}"
        )

        # 如果可用护理员少于启用班次数，启用轮班模式
        if available_caregivers < len(active_shifts):
            self.logger.info("可用护理员少于启用班次数，启用轮班模式")

            # 确保每个启用的班次至少有一个人
            for shift in active_shifts:
                result[shift] = 1

            self.logger.info(f"轮班模式下的班次分配结果: {result}")
            return result

        # 如果护理员足够，按比例分配
        if total_hours > 0:
            # 按工作时长比例分配护理员
            for shift in active_shifts:
                ratio = shift_hours[shift] / total_hours
                result[shift] = max(1, int(available_caregivers * ratio))
        else:
            # 如果没有工作时长信息，均匀分配
            caregivers_per_shift = max(1, available_caregivers // len(active_shifts))
            for shift in active_shifts:
                result[shift] = caregivers_per_shift

        # 确保总人数不超过可用护理员数量
        total_assigned = sum(result.values())

        if total_assigned > available_caregivers:
            # 如果总人数超过可用人数，按比例减少
            excess = total_assigned - available_caregivers

            # 从人数最多的班次开始减少
            shifts = [(shift, result[shift]) for shift in active_shifts]
            # 先按人数排序，人数相同时按班次顺序排序
            shifts.sort(key=lambda x: (-x[1], self.shift_config[x[0]]["order"]))

            for i in range(excess):
                shift_name = shifts[i % len(shifts)][0]
                if result[shift_name] > 1:
                    result[shift_name] -= 1

        self.logger.info(f"班次分配结果: {result}, 总分配人数: {sum(result.values())}")
        return result

    def adjust_shift_times(self, shift_start_time=None):
        """调整班次时间配置，确保班次时间完全连续无空档

        改进的算法，确保：
        1. 班次时间完全连续，无空档
        2. 根据班制模式自动调整班次时长
        3. 正确处理夜班跨天情况
        """
        # 获取当前启用的班次
        active_shifts = self.shift_control["enabled_shifts"]
        self.logger.info(f"当前启用的班次: {active_shifts}")

        # 如果没有启用的班次，使用默认的三班制
        if not active_shifts:
            self.logger.warning("没有启用的班次，使用默认的三班制")
            active_shifts = self.shift_mode_config["three_shift"]["shifts"]

        # 计算每个班次的时长
        total_shifts = len(active_shifts)
        if total_shifts == 0:
            self.logger.warning("没有启用的班次，无法调整班次时间")
            return {}

        # 根据班制模式计算每个班次的时长
        hours_per_shift = 24 / total_shifts
        self.logger.info(f"每个班次的时长: {hours_per_shift} 小时")

        # 如果没有指定起始时间，使用默认的第一个班次开始时间
        if not shift_start_time:
            first_shift = active_shifts[0]
            shift_start_time = self.shift_config[first_shift]["start_time"]
            self.logger.info(f"使用默认的第一个班次开始时间: {shift_start_time}")

        # 解析起始时间
        start_time = self.parse_time(shift_start_time)
        self.logger.info(f"第一个班次开始时间: {start_time}")

        # 计算每个班次的开始和结束时间
        adjusted_config = {}
        current_time_dt = datetime.combine(date.today(), start_time)

        for i, shift in enumerate(active_shifts):
            shift_start = current_time_dt.time()
            shift_start_str = shift_start.strftime("%H:%M")

            # 计算结束时间
            current_time_dt += timedelta(hours=hours_per_shift)
            shift_end = current_time_dt.time()
            shift_end_str = shift_end.strftime("%H:%M")

            # 处理跨天情况
            is_overnight = current_time_dt.date() > date.today()

            # 记录日志
            log_message = f"{shift} 时间: {shift_start_str} - {shift_end_str}"
            if is_overnight:
                log_message += " (跨天)"
            self.logger.info(log_message)

            # 添加到配置中
            adjusted_config[shift] = {
                "start_time": shift_start_str,
                "end_time": shift_end_str,
                "name": (
                    self.shift_config[shift]["name"]
                    if shift in self.shift_config
                    else f"班次{i+1}"
                ),
            }

        # 检查班次时间是否连续
        self.logger.info(f"调整后的班次时间配置: {adjusted_config}")
        return adjusted_config

    def get_activities_by_care_level(self, elder_id, care_level):
        """根据老人的照护需求级别获取适合的活动

        不同照护需求级别的老人需要不同的活动安排：
        - 高级别（3）：需要更多的专业护理活动，如医疗照护、康复训练等
        - 中级别（2）：需要平衡的护理活动和日常生活辅助
        - 低级别（1）：主要需要基本的生活照料和陪伴

        优先级考虑：
        1. 基本生理需求（睡眠、用餐等）始终是最高优先级
        2. 根据照护需求级别选择其他活动

        Args:
            elder_id: 老人ID
            care_level: 照护需求级别（1-3）

        Returns:
            适合该级别老人的活动ID列表，按优先级排序
        """
        # 获取老人的护理动作需求
        elder_demands = Elderdemand.query.filter_by(elder=elder_id, arrange="1").all()
        if not elder_demands:
            self.logger.warning(f"老人 {elder_id} 没有护理动作需求记录")
            return []

        # 解析老人的护理动作需求
        all_action_ids = []
        for demand in elder_demands:
            if demand.actions:
                all_action_ids.extend(
                    [
                        int(action_id.strip())
                        for action_id in demand.actions.split(",")
                        if action_id.strip().isdigit()
                    ]
                )

        if not all_action_ids:
            self.logger.warning(f"老人 {elder_id} 的护理动作需求为空")
            return []

        # 获取护理动作详情
        actions = DicNursingAction.query.filter(
            DicNursingAction.id.in_(all_action_ids)
        ).all()
        if not actions:
            self.logger.warning(f"老人 {elder_id} 的护理动作在数据库中不存在")
            return []

        # 定义基本生理需求活动（最高优先级）
        # 睡眠活动ID为10，用餐相关活动ID为64-73
        essential_activities = [10]  # 睡眠
        meal_activities = [64, 65, 66, 67, 68, 69, 70, 71, 72, 73]  # 用餐相关

        # 定义不同级别的活动类型
        # 高级别照护活动（医疗照护、康复训练等）
        high_level_activities = [
            69,
            85,
            86,
            87,
            88,
            89,
            90,
            154,
            155,
            156,
            157,
            158,
            159,
            160,
            161,
            162,
            163,
            164,
            165,
            166,
        ]
        # 中级别照护活动（日常生活辅助等）
        medium_level_activities = [
            74,
            76,
            77,
            82,
            97,
            100,
            101,
            106,
            108,
            111,
            112,
            113,
            114,
        ]
        # 低级别照护活动（基本生活照料、陪伴等）
        low_level_activities = [
            66,
            67,
            68,
            70,
            71,
            72,
            73,
            95,
            98,
            167,
            168,
            169,
            170,
            171,
            172,
            173,
            174,
            175,
        ]

        # 初始化结果列表
        prioritized_actions = []

        # 第一步：添加基本生理需求活动（如果存在）
        for action in actions:
            # 添加睡眠活动
            if action.id in essential_activities:
                prioritized_actions.append(action.id)
                self.logger.info(
                    f"为老人 {elder_id} 添加基本生理需求活动: {action.name} (ID: {action.id})"
                )

            # 添加用餐相关活动
            if action.id in meal_activities:
                prioritized_actions.append(action.id)
                self.logger.info(
                    f"为老人 {elder_id} 添加用餐相关活动: {action.name} (ID: {action.id})"
                )

        # 第二步：根据照护需求级别添加其他活动
        remaining_actions = []

        if care_level == 3:  # 高级别
            # 高级别老人需要更多的专业护理活动
            # 优先选择高级别活动，然后是中级别活动，最后是低级别活动
            for action in actions:
                if (
                    action.id in high_level_activities
                    and action.id not in prioritized_actions
                ):
                    remaining_actions.append(action.id)

            # 如果高级别活动不足，添加中级别活动
            if len(remaining_actions) < 10:
                for action in actions:
                    if (
                        action.id in medium_level_activities
                        and action.id not in prioritized_actions
                        and action.id not in remaining_actions
                    ):
                        remaining_actions.append(action.id)

            # 如果仍然不足，添加低级别活动
            if len(remaining_actions) < 10:
                for action in actions:
                    if (
                        action.id in low_level_activities
                        and action.id not in prioritized_actions
                        and action.id not in remaining_actions
                    ):
                        remaining_actions.append(action.id)

        elif care_level == 2:  # 中级别
            # 中级别老人需要平衡的护理活动和日常生活辅助
            # 优先选择中级别活动，然后是低级别活动，最后是高级别活动
            for action in actions:
                if (
                    action.id in medium_level_activities
                    and action.id not in prioritized_actions
                ):
                    remaining_actions.append(action.id)

            # 如果中级别活动不足，添加低级别活动
            if len(remaining_actions) < 10:
                for action in actions:
                    if (
                        action.id in low_level_activities
                        and action.id not in prioritized_actions
                        and action.id not in remaining_actions
                    ):
                        remaining_actions.append(action.id)

            # 如果仍然不足，添加高级别活动
            if len(remaining_actions) < 10:
                for action in actions:
                    if (
                        action.id in high_level_activities
                        and action.id not in prioritized_actions
                        and action.id not in remaining_actions
                    ):
                        remaining_actions.append(action.id)

        else:  # 低级别
            # 低级别老人主要需要基本的生活照料和陪伴
            # 优先选择低级别活动，然后是中级别活动
            for action in actions:
                if (
                    action.id in low_level_activities
                    and action.id not in prioritized_actions
                ):
                    remaining_actions.append(action.id)

            # 如果低级别活动不足，添加中级别活动
            if len(remaining_actions) < 10:
                for action in actions:
                    if (
                        action.id in medium_level_activities
                        and action.id not in prioritized_actions
                        and action.id not in remaining_actions
                    ):
                        remaining_actions.append(action.id)

        # 如果过滤后的活动仍然不足，添加其他活动
        if len(remaining_actions) < 10:
            for action in actions:
                if (
                    action.id not in prioritized_actions
                    and action.id not in remaining_actions
                ):
                    remaining_actions.append(action.id)
                if len(prioritized_actions) + len(remaining_actions) >= 10:
                    break

        # 随机打乱非优先级活动列表，避免每次生成相同的活动序列
        random.shuffle(remaining_actions)

        # 合并优先级活动和其他活动
        final_activities = prioritized_actions + remaining_actions

        self.logger.info(
            f"为老人 {elder_id} 的照护需求级别 {care_level} 选择了 {len(final_activities)} 个活动，其中优先级活动 {len(prioritized_actions)} 个"
        )
        return final_activities

    def match_caregiver_to_elder_needs(self, caregivers, elder_actions):
        """根据老人需求匹配最合适的护理员

        匹配策略：
        1. 首先考虑技能匹配度（能够满足老人需求的技能数量）
        2. 其次考虑护理员的工作负荷（已分配的时间段数量）
        3. 最后考虑护理员的技能多样性（避免浪费高技能护理员）
        """
        # 将老人需要的护理动作转换为整数列表
        elder_action_ids = self.parse_skills(elder_actions)
        if not elder_action_ids:
            self.logger.warning(f"老人需求为空：{elder_actions}")
            return None

        # 记录所有匹配的护理员及其分数
        matched_caregivers = []

        for caregiver in caregivers:
            # 解析护理员技能
            caregiver_skills = self.parse_skills(caregiver.skills)
            if not caregiver_skills:
                self.logger.warning(f"护理员 {caregiver.attendant_name} 没有技能记录")
                continue

            # 计算匹配分数（匹配的技能数量）
            match_score = sum(
                1 for action in elder_action_ids if action in caregiver_skills
            )

            # 如果有匹配的技能，则添加到候选列表
            if match_score > 0:
                # 计算护理员的工作负荷（已分配的时间段数量）
                workload = TimeSlot.query.filter_by(
                    caregiver_id=caregiver.id, schedule_date=date.today()
                ).count()

                # 计算技能多样性分数（技能数量与匹配分数的比值）
                # 这个分数越高，表示护理员有更多不需要的技能，应该优先保留给更需要的老人
                skill_diversity = len(caregiver_skills) / max(match_score, 1)

                matched_caregivers.append(
                    {
                        "caregiver": caregiver,
                        "match_score": match_score,
                        "workload": workload,
                        "skill_diversity": skill_diversity,
                    }
                )

        if not matched_caregivers:
            self.logger.warning(f"没有找到匹配的护理员来满足老人需求: {elder_actions}")
            # 如果没有匹配的护理员，但有可用的护理员，则随机选择一个
            if caregivers:
                random_caregiver = random.choice(caregivers)
                self.logger.warning(f"随机选择护理员 {random_caregiver.attendant_name}")
                return random_caregiver
            return None

        # 按匹配分数降序排序
        matched_caregivers.sort(
            key=lambda x: (-x["match_score"], x["workload"], x["skill_diversity"])
        )

        # 返回最佳匹配
        best_match = matched_caregivers[0]["caregiver"]
        self.logger.info(
            f"为老人需求 {elder_actions} 匹配到护理员 {best_match.attendant_name}"
        )
        return best_match

    def check_caregiver_availability(self, caregiver_id, target_date, time_slot):
        """检查护理员在指定时间段是否可用

        注意：此方法已修改，不再从数据库查询，而是使用内存中的可用性数据
        """
        # 使用内存中的字典检查护理员可用性
        if not hasattr(self, "_caregiver_availability"):
            self._caregiver_availability = {}

        # 使用元组作为字典键
        key = (caregiver_id, target_date.isoformat(), time_slot)

        # 如果键不存在或者值为True，则该护理员在该时间段可用
        return self._caregiver_availability.get(key, True)

    def update_caregiver_availability(
        self, caregiver_id, target_date, time_slot, is_available=False
    ):
        """更新护理员在指定时间段的可用性

        注意：此方法已修改，不再向caregiver_schedules表写入数据
        仅在内存中跟踪护理员可用性，用于排班算法内部使用
        """
        # 使用内存中的字典跟踪护理员可用性，而不是写入数据库
        if not hasattr(self, "_caregiver_availability"):
            self._caregiver_availability = {}

        # 使用元组作为字典键
        key = (caregiver_id, target_date.isoformat(), time_slot)
        self._caregiver_availability[key] = is_available

        self.logger.info(
            f"更新护理员 {caregiver_id} 在 {target_date} 时间段 {time_slot} 的可用性为 {is_available}（仅内存中）"
        )

    def optimize_schedule(self, initial_schedule, caregivers):
        """使用算法优化排班方案

        复用原接口的遗传算法和模拟退火算法，优化排班方案

        如果增强版算法可用，将使用增强版算法优化排班方案

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        # 检查增强版算法是否可用
        if (
            hasattr(self, "enhanced_nsga2_optimizer")
            and hasattr(self, "enhanced_sa")
            and hasattr(self, "enhanced_rl")
        ):
            self.logger.info("增强版算法可用，将使用增强版算法优化排班方案")
            return self.enhanced_optimize(initial_schedule, caregivers)

        self.logger.info("开始使用混合算法优化排班方案...")

        # 初始化种群
        population = [initial_schedule]
        for _ in range(self.population_size - 1):
            # 生成变异的排班方案
            variant = self.create_schedule_variant(initial_schedule, caregivers)
            population.append(variant)

        best_schedule = initial_schedule
        best_fitness = self.evaluate_schedule(best_schedule, caregivers)
        self.logger.info(f"初始适应度: {best_fitness}")

        # 重置模拟退火温度
        self.temperature = self.initial_temperature

        # 遗传算法迭代
        for generation in range(self.phenotype_limit):
            # 计算适应度
            fitness_values = [
                self.evaluate_schedule(schedule, caregivers) for schedule in population
            ]

            # 找到最佳解
            max_index = fitness_values.index(max(fitness_values))
            if fitness_values[max_index] > best_fitness:
                best_schedule = population[max_index]
                best_fitness = fitness_values[max_index]
                self.logger.info(
                    f"第 {generation} 代发现更好的解，适应度: {best_fitness}"
                )

            # 选择父代
            parents = self.select_parents(population, fitness_values)

            # 交叉和变异
            new_population = []
            for i in range(0, len(parents), 2):
                if i + 1 < len(parents):
                    # 交叉
                    if random.random() < self.crossover_rate:
                        child1, child2 = self.crossover(parents[i], parents[i + 1])
                        new_population.extend([child1, child2])
                    else:
                        new_population.extend([parents[i], parents[i + 1]])

            # 变异
            for i in range(len(new_population)):
                if random.random() < self.mutation_rate:
                    new_population[i] = self.mutate(new_population[i], caregivers)

            # 模拟退火优化
            for i in range(len(new_population)):
                new_population[i] = self.simulated_annealing(
                    new_population[i], caregivers
                )

            # 保留精英
            elite_count = self.population_size - self.elimination_size
            sorted_indices = sorted(
                range(len(fitness_values)),
                key=lambda i: fitness_values[i],
                reverse=True,
            )
            elite = [population[i] for i in sorted_indices[:elite_count]]

            # 更新种群
            population = elite + new_population[: self.population_size - len(elite)]

            # 更新温度
            self.temperature *= self.cooling_rate

            if generation % 10 == 0:
                self.logger.info(
                    f"第 {generation} 代，最佳适应度: {best_fitness}, 当前温度: {self.temperature:.2f}"
                )

        self.logger.info(f"混合算法优化完成，最终适应度: {best_fitness}")
        return best_schedule

    def genetic_algorithm_optimize(self, initial_schedule, caregivers):
        """仅使用遗传算法优化排班方案

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用遗传算法优化排班方案...")

        # 初始化种群
        population = [initial_schedule]
        for _ in range(self.population_size - 1):
            # 生成变异的排班方案
            variant = self.create_schedule_variant(initial_schedule, caregivers)
            population.append(variant)

        best_schedule = initial_schedule
        best_fitness = self.evaluate_schedule(best_schedule, caregivers)
        self.logger.info(f"初始适应度: {best_fitness}")

        # 遗传算法迭代
        for generation in range(self.phenotype_limit):
            # 计算适应度
            fitness_values = [
                self.evaluate_schedule(schedule, caregivers) for schedule in population
            ]

            # 找到最佳解
            max_index = fitness_values.index(max(fitness_values))
            if fitness_values[max_index] > best_fitness:
                best_schedule = population[max_index]
                best_fitness = fitness_values[max_index]
                self.logger.info(
                    f"第 {generation} 代发现更好的解，适应度: {best_fitness}"
                )

            # 选择父代
            parents = self.select_parents(population, fitness_values)

            # 交叉和变异
            new_population = []
            for i in range(0, len(parents), 2):
                if i + 1 < len(parents):
                    # 交叉
                    if random.random() < self.crossover_rate:
                        child1, child2 = self.crossover(parents[i], parents[i + 1])
                        new_population.extend([child1, child2])
                    else:
                        new_population.extend([parents[i], parents[i + 1]])

            # 变异
            for i in range(len(new_population)):
                if random.random() < self.mutation_rate:
                    new_population[i] = self.mutate(new_population[i], caregivers)

            # 保留精英
            elite_count = self.population_size - self.elimination_size
            sorted_indices = sorted(
                range(len(fitness_values)),
                key=lambda i: fitness_values[i],
                reverse=True,
            )
            elite = [population[i] for i in sorted_indices[:elite_count]]

            # 更新种群
            population = elite + new_population[: self.population_size - len(elite)]

            # 每10代输出一次日志
            if generation % 10 == 0:
                self.logger.info(
                    f"第 {generation} 代完成，当前最佳适应度: {best_fitness}"
                )

        self.logger.info(f"遗传算法优化完成，最终适应度: {best_fitness}")
        return best_schedule

    def enhanced_optimize(self, initial_schedule, caregivers):
        """使用增强版算法优化排班方案

        这个方法会根据排班方案的特点自动选择最适合的算法进行优化

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用增强版算法优化排班方案...")

        # 检查高级算法是否可用
        if (
            not hasattr(self, "enhanced_nsga2_optimizer")
            or not hasattr(self, "enhanced_sa")
            or not hasattr(self, "enhanced_rl")
        ):
            self.logger.warning("增强版算法不可用，将使用混合算法代替")
            return self.optimize_schedule(initial_schedule, caregivers)

        # 评估初始排班方案
        initial_fitness = self.evaluate_schedule(initial_schedule, caregivers)
        self.logger.info(f"初始排班方案适应度: {initial_fitness}")

        # 分析排班方案特点
        schedule_features = self.analyze_schedule_features(initial_schedule, caregivers)

        # 根据排班方案特点选择最适合的算法
        algorithm_scores = self.select_best_algorithm(schedule_features)
        best_algorithm = max(algorithm_scores, key=algorithm_scores.get)

        self.logger.info(f"选择的最佳算法: {best_algorithm}")

        # 根据选择的算法进行优化
        if best_algorithm == "enhanced_nsga2":
            optimized_schedule = self.enhanced_nsga2_optimize(
                initial_schedule, caregivers
            )
        elif best_algorithm == "enhanced_sa":
            optimized_schedule = self.enhanced_sa_optimize(initial_schedule, caregivers)
        elif best_algorithm == "enhanced_rl":
            optimized_schedule = self.enhanced_rl_optimize(initial_schedule, caregivers)
        else:
            # 默认使用增强版NSGA-II算法
            optimized_schedule = self.enhanced_nsga2_optimize(
                initial_schedule, caregivers
            )

        # 评估优化后的排班方案
        optimized_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        improvement = (
            ((optimized_fitness - initial_fitness) / initial_fitness) * 100
            if initial_fitness > 0
            else 0
        )

        self.logger.info(
            f"增强版算法优化完成，初始适应度: {initial_fitness}, 优化后适应度: {optimized_fitness}, 改进百分比: {improvement:.2f}%"
        )

        return optimized_schedule

    def analyze_schedule_features(self, schedule, caregivers):
        """分析排班方案的特点

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            排班方案特点字典
        """
        features = {}

        # 1. 计算排班方案的规模
        features["schedule_size"] = len(schedule)

        # 2. 计算护理员数量
        features["caregiver_count"] = len(caregivers)

        # 3. 计算班次分布
        shift_distribution = {}
        for assignment in schedule:
            shift = assignment.get("shift", "")
            if shift not in shift_distribution:
                shift_distribution[shift] = 0
            shift_distribution[shift] += 1
        features["shift_distribution"] = shift_distribution

        # 4. 计算班次分布的均衡性
        if shift_distribution:
            values = list(shift_distribution.values())
            features["shift_balance"] = 1 - (max(values) - min(values)) / (
                sum(values) + 1e-10
            )
        else:
            features["shift_balance"] = 0

        # 5. 计算每个护理员的工作负载
        workload = {}
        for assignment in schedule:
            caregiver_id = assignment.get("caregiver_id", "")
            if caregiver_id not in workload:
                workload[caregiver_id] = 0
            workload[caregiver_id] += 1
        features["workload"] = workload

        # 6. 计算工作负载的均衡性
        if workload:
            values = list(workload.values())
            features["workload_balance"] = 1 - (max(values) - min(values)) / (
                sum(values) + 1e-10
            )
        else:
            features["workload_balance"] = 0

        # 7. 计算排班方案的复杂性
        features["complexity"] = features["schedule_size"] * features["caregiver_count"]

        return features

    def select_best_algorithm(self, schedule_features):
        """根据排班方案特点选择最适合的算法

        Args:
            schedule_features: 排班方案特点字典

        Returns:
            算法评分字典
        """
        algorithm_scores = {"enhanced_nsga2": 0, "enhanced_sa": 0, "enhanced_rl": 0}

        # 1. 根据排班方案规模评分
        schedule_size = schedule_features.get("schedule_size", 0)
        if schedule_size < 50:
            algorithm_scores["enhanced_sa"] += 3
            algorithm_scores["enhanced_rl"] += 2
            algorithm_scores["enhanced_nsga2"] += 1
        elif schedule_size < 200:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_rl"] += 1
        else:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_rl"] += 2
            algorithm_scores["enhanced_sa"] += 1

        # 2. 根据护理员数量评分
        caregiver_count = schedule_features.get("caregiver_count", 0)
        if caregiver_count < 10:
            algorithm_scores["enhanced_sa"] += 3
            algorithm_scores["enhanced_rl"] += 2
            algorithm_scores["enhanced_nsga2"] += 1
        elif caregiver_count < 30:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_rl"] += 1
        else:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_rl"] += 2
            algorithm_scores["enhanced_sa"] += 1

        # 3. 根据班次分布的均衡性评分
        shift_balance = schedule_features.get("shift_balance", 0)
        if shift_balance < 0.3:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_rl"] += 1
        elif shift_balance < 0.7:
            algorithm_scores["enhanced_sa"] += 3
            algorithm_scores["enhanced_nsga2"] += 2
            algorithm_scores["enhanced_rl"] += 1
        else:
            algorithm_scores["enhanced_rl"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_nsga2"] += 1

        # 4. 根据工作负载的均衡性评分
        workload_balance = schedule_features.get("workload_balance", 0)
        if workload_balance < 0.3:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_rl"] += 1
        elif workload_balance < 0.7:
            algorithm_scores["enhanced_sa"] += 3
            algorithm_scores["enhanced_nsga2"] += 2
            algorithm_scores["enhanced_rl"] += 1
        else:
            algorithm_scores["enhanced_rl"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_nsga2"] += 1

        # 5. 根据排班方案的复杂性评分
        complexity = schedule_features.get("complexity", 0)
        if complexity < 500:
            algorithm_scores["enhanced_sa"] += 3
            algorithm_scores["enhanced_rl"] += 2
            algorithm_scores["enhanced_nsga2"] += 1
        elif complexity < 5000:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_sa"] += 2
            algorithm_scores["enhanced_rl"] += 1
        else:
            algorithm_scores["enhanced_nsga2"] += 3
            algorithm_scores["enhanced_rl"] += 2
            algorithm_scores["enhanced_sa"] += 1

        return algorithm_scores

    def enhanced_nsga2_optimize(self, initial_schedule, caregivers):
        """使用增强版NSGA-II多目标优化算法优化排班方案

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用增强版NSGA-II算法优化排班方案...")

        # 检查增强版NSGA-II算法是否可用
        if not hasattr(self, "enhanced_nsga2_optimizer"):
            self.logger.warning("增强版NSGA-II算法不可用，将使用基本遗传算法代替")
            return self.genetic_algorithm_optimize(initial_schedule, caregivers)

        # 定义目标函数
        def objective_functions(schedule):
            # 计算多个目标函数值
            # 1. 班次覆盖率
            coverage_score = self.evaluate_coverage(schedule)

            # 2. 护理员工作负载平衡度
            balance_score = self.evaluate_workload_balance(schedule, caregivers)

            # 3. 技能匹配度
            skill_match_score = self.evaluate_skill_match(schedule, caregivers)

            # 4. 护理员偏好满足度
            preference_score = self.evaluate_preference(schedule, caregivers)

            # 5. 排班连续性
            continuity_score = self.evaluate_continuity(schedule)

            # 返回多个目标函数值
            return [
                coverage_score,
                balance_score,
                skill_match_score,
                preference_score,
                continuity_score,
            ]

        # 创建变异解决方案的函数
        def create_variant_func(solution, context):
            return self.create_schedule_variant(solution, context)

        # 交叉函数
        def crossover_func(parent1, parent2):
            return self.crossover(parent1, parent2)

        # 变异函数
        def mutate_func(solution, context):
            return self.mutate(solution, context)

        # 局部搜索函数
        def local_search_func(solution, context):
            # 使用模拟退火算法进行局部搜索
            return self.simulated_annealing(solution, context)

        # 使用增强版NSGA-II算法优化排班方案
        optimized_schedule = self.enhanced_nsga2_optimizer.optimize(
            initial_solution=initial_schedule,
            objective_functions=[lambda s: objective_functions(s)[i] for i in range(5)],
            create_variant_func=create_variant_func,
            crossover_func=crossover_func,
            mutate_func=mutate_func,
            local_search_func=local_search_func,
            context=caregivers,
        )

        # 评估优化后的排班方案
        optimized_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        initial_fitness = self.evaluate_schedule(initial_schedule, caregivers)
        improvement = (
            ((optimized_fitness - initial_fitness) / initial_fitness) * 100
            if initial_fitness > 0
            else 0
        )

        self.logger.info(
            f"增强版NSGA-II算法优化完成，初始适应度: {initial_fitness}, 优化后适应度: {optimized_fitness}, 改进百分比: {improvement:.2f}%"
        )

        return optimized_schedule

    def enhanced_sa_optimize(self, initial_schedule, caregivers):
        """使用增强版模拟退火算法优化排班方案

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用增强版模拟退火算法优化排班方案...")

        # 检查增强版模拟退火算法是否可用
        if not hasattr(self, "enhanced_sa"):
            self.logger.warning("增强版模拟退火算法不可用，将使用基本模拟退火算法代替")
            return self.simulated_annealing_optimize(initial_schedule, caregivers)

        # 定义评估函数
        def evaluate_func(schedule):
            return self.evaluate_schedule(schedule, caregivers)

        # 定义生成领域解的函数
        def generate_neighbor_func(schedule, context):
            # 生成领域解
            return self.create_schedule_variant(schedule, context)

        # 定义局部搜索函数
        def local_search_func(schedule, context):
            # 使用遗传算法进行局部搜索
            return self.genetic_algorithm_optimize(schedule, context)

        # 使用增强版模拟退火算法优化排班方案
        optimized_schedule = self.enhanced_sa.optimize(
            initial_solution=initial_schedule,
            evaluate_func=evaluate_func,
            generate_neighbor_func=generate_neighbor_func,
            local_search_func=local_search_func,
            context=caregivers,
        )

        # 评估优化后的排班方案
        optimized_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        initial_fitness = self.evaluate_schedule(initial_schedule, caregivers)
        improvement = (
            ((optimized_fitness - initial_fitness) / initial_fitness) * 100
            if initial_fitness > 0
            else 0
        )

        self.logger.info(
            f"增强版模拟退火算法优化完成，初始适应度: {initial_fitness}, 优化后适应度: {optimized_fitness}, 改进百分比: {improvement:.2f}%"
        )

        return optimized_schedule

    def enhanced_rl_optimize(self, initial_schedule, caregivers):
        """使用增强版强化学习算法优化排班方案

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用增强版强化学习算法优化排班方案...")

        # 检查增强版强化学习算法是否可用
        if not hasattr(self, "enhanced_rl"):
            self.logger.warning("增强版强化学习算法不可用，将使用混合算法代替")
            return self.optimize_schedule(initial_schedule, caregivers)

        # 定义获取状态的函数
        def get_state_func(schedule):
            # 将排班方案转换为状态表示
            features = self.analyze_schedule_features(schedule, caregivers)
            state = (
                features.get("schedule_size", 0),
                features.get("caregiver_count", 0),
                features.get("shift_balance", 0),
                features.get("workload_balance", 0),
                features.get("complexity", 0),
            )
            return state

        # 定义获取可用动作的函数
        def get_actions_func(_):
            # 返回可用的动作列表
            # 动作包括：交换两个护理员的班次、重新分配护理员等
            actions = [
                "swap_caregivers",
                "reassign_caregiver",
                "swap_shifts",
                "optimize_local",
            ]
            return actions

        # 定义执行动作的函数
        def take_action_func(schedule, action, context):
            # 根据动作类型执行相应的操作
            if action == "swap_caregivers":
                # 交换两个护理员的班次
                return self.swap_caregivers(schedule, context)
            elif action == "reassign_caregiver":
                # 重新分配护理员
                return self.reassign_caregiver(schedule, context)
            elif action == "swap_shifts":
                # 交换两个班次
                return self.swap_shifts(schedule, context)
            elif action == "optimize_local":
                # 局部优化
                return self.simulated_annealing(schedule, context)
            else:
                # 默认返回原排班方案
                return schedule

        # 定义获取奖励的函数
        def get_reward_func(schedule):
            # 计算奖励值
            return self.evaluate_schedule(schedule, caregivers)

        # 定义判断是否为终止状态的函数
        def is_terminal_func(_):
            # 判断是否为终止状态
            # 在强化学习中，我们通常不使用终止状态，而是通过回合数控制
            return False

        # 使用增强版强化学习算法优化排班方案
        optimized_schedule = self.enhanced_rl.optimize(
            initial_solution=initial_schedule,
            get_state_func=get_state_func,
            get_actions_func=get_actions_func,
            take_action_func=take_action_func,
            get_reward_func=get_reward_func,
            is_terminal_func=is_terminal_func,
            context=caregivers,
        )

        # 评估优化后的排班方案
        optimized_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        initial_fitness = self.evaluate_schedule(initial_schedule, caregivers)
        improvement = (
            ((optimized_fitness - initial_fitness) / initial_fitness) * 100
            if initial_fitness > 0
            else 0
        )

        self.logger.info(
            f"增强版强化学习算法优化完成，初始适应度: {initial_fitness}, 优化后适应度: {optimized_fitness}, 改进百分比: {improvement:.2f}%"
        )

        return optimized_schedule

    def swap_caregivers(self, schedule, _):
        """交换两个护理员的班次

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            交换后的排班方案
        """
        # 复制排班方案，避免修改原始排班方案
        new_schedule = copy.deepcopy(schedule)

        # 如果排班方案为空或只有一个元素，直接返回
        if len(new_schedule) <= 1:
            return new_schedule

        # 随机选择两个不同的索引
        idx1, idx2 = random.sample(range(len(new_schedule)), 2)

        # 交换两个护理员
        caregiver_id1 = new_schedule[idx1].get("caregiver_id", "")
        caregiver_id2 = new_schedule[idx2].get("caregiver_id", "")

        # 检查两个护理员的班次是否相同
        shift1 = new_schedule[idx1].get("shift", "")
        shift2 = new_schedule[idx2].get("shift", "")

        # 如果班次相同，直接交换护理员
        if shift1 == shift2:
            new_schedule[idx1]["caregiver_id"] = caregiver_id2
            new_schedule[idx2]["caregiver_id"] = caregiver_id1

            # 如果有护理员名称字段，也交换
            if (
                "caregiver_name" in new_schedule[idx1]
                and "caregiver_name" in new_schedule[idx2]
            ):
                caregiver_name1 = new_schedule[idx1].get("caregiver_name", "")
                caregiver_name2 = new_schedule[idx2].get("caregiver_name", "")
                new_schedule[idx1]["caregiver_name"] = caregiver_name2
                new_schedule[idx2]["caregiver_name"] = caregiver_name1

        return new_schedule

    def reassign_caregiver(self, schedule, caregivers):
        """重新分配护理员

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            重新分配后的排班方案
        """
        # 复制排班方案，避免修改原始排班方案
        new_schedule = copy.deepcopy(schedule)

        # 如果排班方案为空或护理员列表为空，直接返回
        if not new_schedule or not caregivers:
            return new_schedule

        # 随机选择一个排班元素
        idx = random.randint(0, len(new_schedule) - 1)

        # 随机选择一个护理员
        caregiver = random.choice(caregivers)

        # 重新分配护理员
        new_schedule[idx]["caregiver_id"] = (
            caregiver.id if hasattr(caregiver, "id") else str(caregiver.get("id", ""))
        )

        # 如果有护理员名称字段，也更新
        if "caregiver_name" in new_schedule[idx]:
            new_schedule[idx]["caregiver_name"] = (
                caregiver.name
                if hasattr(caregiver, "name")
                else str(caregiver.get("name", ""))
            )

        return new_schedule

    def swap_shifts(self, schedule, _):
        """交换两个班次

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            交换后的排班方案
        """
        # 复制排班方案，避免修改原始排班方案
        new_schedule = copy.deepcopy(schedule)

        # 如果排班方案为空或只有一个元素，直接返回
        if len(new_schedule) <= 1:
            return new_schedule

        # 随机选择两个不同的索引
        idx1, idx2 = random.sample(range(len(new_schedule)), 2)

        # 交换两个班次
        shift1 = new_schedule[idx1].get("shift", "")
        shift2 = new_schedule[idx2].get("shift", "")

        # 交换班次
        new_schedule[idx1]["shift"] = shift2
        new_schedule[idx2]["shift"] = shift1

        return new_schedule

    def simulated_annealing_optimize(self, initial_schedule, caregivers):
        """仅使用模拟退火算法优化排班方案

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用模拟退火算法优化排班方案...")

        # 重置温度
        self.temperature = self.initial_temperature

        current = initial_schedule
        current_fitness = self.evaluate_schedule(current, caregivers)
        best_schedule = current
        best_fitness = current_fitness

        self.logger.info(f"初始适应度: {best_fitness}")

        # 记录连续无改进的次数
        no_improvement_count = 0
        max_no_improvement = 20
        max_temperature = self.initial_temperature * 10  # 设置最大温度

        # 模拟退火迭代
        for iteration in range(self.phenotype_limit * 10):  # 模拟退火需要更多的迭代
            # 生成领域解
            neighbor = self.mutate(current, caregivers)
            neighbor_fitness = self.evaluate_schedule(neighbor, caregivers)

            # 计算适应度差异
            delta = neighbor_fitness - current_fitness

            # 如果领域解更好，或者满足模拟退火接受条件，则接受领域解
            if delta > 0 or random.random() < math.exp(
                delta / max(self.temperature, 0.01)
            ):
                current = neighbor
                current_fitness = neighbor_fitness

                # 如果发现更好的解，更新最佳解
                if current_fitness > best_fitness:
                    best_schedule = current
                    best_fitness = current_fitness
                    self.logger.info(
                        f"第 {iteration} 次迭代发现更好的解，适应度: {best_fitness}"
                    )
                    no_improvement_count = 0
                else:
                    no_improvement_count += 1
            else:
                no_improvement_count += 1

            # 如果连续多次没有改进，提高温度，但不超过最大温度
            if no_improvement_count >= max_no_improvement:
                self.temperature = min(
                    self.temperature * 1.5, max_temperature
                )  # 提高温度，但不超过最大温度
                self.logger.info(
                    f"连续 {max_no_improvement} 次没有改进，提高温度至 {self.temperature:.2f}"
                )
                no_improvement_count = 0
            else:
                # 正常冷却
                self.temperature *= self.cooling_rate

            # 每100次迭代输出一次日志
            if iteration % 100 == 0:
                self.logger.info(
                    f"第 {iteration} 次迭代完成，当前最佳适应度: {best_fitness}, 当前温度: {self.temperature:.2f}"
                )

            # 如果温度过低，结束迭代
            if self.temperature < 0.01:
                self.logger.info(f"温度过低 ({self.temperature:.4f})，结束迭代")
                break

        self.logger.info(f"模拟退火算法优化完成，最终适应度: {best_fitness}")
        return best_schedule

    def create_schedule_variant(self, schedule, caregivers):
        """创建排班方案的变异

        Args:
            schedule: 原始排班方案
            caregivers: 护理员列表

        Returns:
            变异的排班方案
        """
        # 深拷贝原始排班方案
        variant = {
            "shift_assignments": schedule["shift_assignments"].copy(),
            "elder_schedules": {
                k: v.copy() for k, v in schedule["elder_schedules"].items()
            },
            "time_slot_assignments": (
                schedule["time_slot_assignments"].copy()
                if "time_slot_assignments" in schedule
                else []
            ),
        }

        # 随机修改班次分配
        if variant["shift_assignments"]:
            # 随机选择一些班次分配进行修改
            num_to_modify = max(
                1, int(len(variant["shift_assignments"]) * 0.2)
            )  # 修改约20%的班次分配
            indices_to_modify = random.sample(
                range(len(variant["shift_assignments"])), num_to_modify
            )

            for idx in indices_to_modify:
                # 随机选择一个新的护理员
                new_caregiver = random.choice(caregivers)
                variant["shift_assignments"][idx].caregiver_id = new_caregiver.id
                variant["shift_assignments"][
                    idx
                ].caregiver_name = new_caregiver.attendant_name

        return variant

    def evaluate_schedule(self, schedule, caregivers):
        """评估排班方案的质量

        采用与原接口类似的累加方式计算适应度，而不是加权平均

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            适应度分数
        """
        # 1. 评估班次覆盖率（每个班次都有足够的护理员）
        coverage_score = self.evaluate_coverage(schedule) * 100  # 乘以100增加权重

        # 2. 评估护理员工作负载平衡度（工作量分配均匀）
        balance_score = (
            self.evaluate_workload_balance(schedule, caregivers) * 80
        )  # 乘以80增加权重

        # 3. 评估技能匹配度（护理员技能与老人需求匹配）
        skill_match_score = (
            self.evaluate_skill_match(schedule, caregivers) * 60
        )  # 乘以60增加权重

        # 4. 评估护理员偏好满足度（满足护理员的班次偏好）
        preference_score = (
            self.evaluate_preference(schedule, caregivers) * 40
        )  # 乘以40增加权重

        # 5. 评估排班连续性（避免频繁切换班次）
        continuity_score = self.evaluate_continuity(schedule) * 40  # 乘以40增加权重

        # 6. 奖励非睡眠活动（参考原接口）
        non_sleep_activity_score = (
            self.evaluate_non_sleep_activity(schedule) * 30
        )  # 乘以30增加权重

        # 7. 奖励活动多样性（参考原接口）
        activity_diversity_score = (
            self.evaluate_activity_diversity(schedule) * 20
        )  # 乘以20增加权重

        # 总适应度是所有因素的和
        score = (
            coverage_score
            + balance_score
            + skill_match_score
            + preference_score
            + continuity_score
            + non_sleep_activity_score
            + activity_diversity_score
        )

        # 记录各项评分
        self.logger.debug(
            f"评估排班方案: 覆盖率={coverage_score:.2f}, 平衡度={balance_score:.2f}, "
            f"技能匹配={skill_match_score:.2f}, 偏好满足={preference_score:.2f}, "
            f"连续性={continuity_score:.2f}, 非睡眠活动={non_sleep_activity_score:.2f}, "
            f"活动多样性={activity_diversity_score:.2f}, 总分={score:.2f}"
        )

        return score

    def evaluate_coverage(self, schedule):
        """评估班次覆盖率

        Args:
            schedule: 排班方案

        Returns:
            覆盖率分数 (0-1)
        """
        if "shift_assignments" not in schedule or not schedule["shift_assignments"]:
            return 0

        # 按日期和班次类型分组
        shifts_by_date = {}
        for assignment in schedule["shift_assignments"]:
            date_key = (
                assignment.shift_date.isoformat()
                if hasattr(assignment.shift_date, "isoformat")
                else str(assignment.shift_date)
            )
            if date_key not in shifts_by_date:
                shifts_by_date[date_key] = set()
            shifts_by_date[date_key].add(assignment.shift_type)

        # 计算每天的覆盖率
        total_coverage = 0
        active_shifts_count = len(self.shift_control["enabled_shifts"])
        if active_shifts_count == 0:
            return 0

        for date_key, shift_types in shifts_by_date.items():
            coverage = len(shift_types) / active_shifts_count
            total_coverage += coverage

        # 计算平均覆盖率
        if shifts_by_date:
            return total_coverage / len(shifts_by_date)
        return 0

    def evaluate_workload_balance(self, schedule, caregivers):
        """评估护理员工作负载平衡度

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            平衡度分数 (0-1)
        """
        if (
            "shift_assignments" not in schedule
            or not schedule["shift_assignments"]
            or not caregivers
        ):
            return 0

        # 统计每个护理员的班次数
        caregiver_shifts = {}
        for assignment in schedule["shift_assignments"]:
            caregiver_id = assignment.caregiver_id
            caregiver_shifts[caregiver_id] = caregiver_shifts.get(caregiver_id, 0) + 1

        # 为所有护理员创建记录，包括未分配班次的护理员
        for caregiver in caregivers:
            if caregiver.id not in caregiver_shifts:
                caregiver_shifts[caregiver.id] = 0

        # 计算标准差
        if caregiver_shifts:
            shift_counts = list(caregiver_shifts.values())
            mean_shifts = sum(shift_counts) / len(shift_counts)

            # 避免除以零
            if mean_shifts == 0:
                return 1  # 如果所有护理员都没有班次，认为是平衡的

            std_dev = (
                sum((count - mean_shifts) ** 2 for count in shift_counts)
                / len(shift_counts)
            ) ** 0.5

            # 标准差越小，平衡度越高
            # 使用指数衰减函数将标准差映射到0-1范围
            balance_score = math.exp(-std_dev / mean_shifts)
            return balance_score

        return 0

    def evaluate_skill_match(self, schedule, caregivers):
        """评估技能匹配度

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            技能匹配度分数 (0-1)
        """
        if (
            "time_slot_assignments" not in schedule
            or not schedule["time_slot_assignments"]
        ):
            return 0

        total_matches = 0
        total_slots = len(schedule["time_slot_assignments"])

        if total_slots == 0:
            return 0

        for slot in schedule["time_slot_assignments"]:
            # 找到该时间段的护理员
            caregiver = next((c for c in caregivers if c.id == slot.caregiver_id), None)
            if caregiver:
                # 检查护理员技能是否匹配活动需求
                caregiver_skills = self.parse_skills(caregiver.skills)
                activity_id = (
                    int(slot.activity_id)
                    if hasattr(slot, "activity_id")
                    and slot.activity_id
                    and slot.activity_id.isdigit()
                    else 0
                )

                if activity_id in caregiver_skills:
                    total_matches += 1

        return total_matches / total_slots

    def evaluate_preference(self, schedule, caregivers):
        """评估护理员偏好满足度

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            偏好满足度分数 (0-1)
        """
        if "shift_assignments" not in schedule or not schedule["shift_assignments"]:
            return 0

        # 假设每个护理员有偏好的班次类型
        # 这里简化处理，随机生成偏好
        caregiver_preferences = {}
        for caregiver in caregivers:
            # 随机生成偏好班次类型
            preferred_shifts = random.sample(
                list(self.shift_control["enabled_shifts"]),
                min(2, len(self.shift_control["enabled_shifts"])),
            )
            caregiver_preferences[caregiver.id] = preferred_shifts

        # 计算偏好满足度
        total_matches = 0
        total_assignments = len(schedule["shift_assignments"])

        if total_assignments == 0:
            return 0

        for assignment in schedule["shift_assignments"]:
            caregiver_id = assignment.caregiver_id
            if (
                caregiver_id in caregiver_preferences
                and assignment.shift_type in caregiver_preferences[caregiver_id]
            ):
                total_matches += 1

        return total_matches / total_assignments

    def evaluate_continuity(self, schedule):
        """评估排班连续性

        Args:
            schedule: 排班方案

        Returns:
            连续性分数 (0-1)
        """
        if "shift_assignments" not in schedule or not schedule["shift_assignments"]:
            return 0

        # 按护理员和日期分组
        caregiver_schedules = {}
        for assignment in schedule["shift_assignments"]:
            caregiver_id = assignment.caregiver_id
            date_key = (
                assignment.shift_date.isoformat()
                if hasattr(assignment.shift_date, "isoformat")
                else str(assignment.shift_date)
            )

            if caregiver_id not in caregiver_schedules:
                caregiver_schedules[caregiver_id] = {}

            if date_key not in caregiver_schedules[caregiver_id]:
                caregiver_schedules[caregiver_id][date_key] = []

            caregiver_schedules[caregiver_id][date_key].append(assignment.shift_type)

        # 计算连续工作天数
        continuity_score = 0
        total_caregivers = len(caregiver_schedules)

        if total_caregivers == 0:
            return 0

        for caregiver_id, dates in caregiver_schedules.items():
            # 按日期排序
            sorted_dates = sorted(dates.keys())

            # 计算最长连续工作天数
            max_consecutive = 0
            current_consecutive = 0

            for i in range(len(sorted_dates)):
                if i > 0:
                    # 检查是否是连续的日期
                    prev_date = datetime.strptime(
                        sorted_dates[i - 1], "%Y-%m-%d"
                    ).date()
                    curr_date = datetime.strptime(sorted_dates[i], "%Y-%m-%d").date()

                    if (curr_date - prev_date).days == 1:
                        current_consecutive += 1
                    else:
                        current_consecutive = 1
                else:
                    current_consecutive = 1

                max_consecutive = max(max_consecutive, current_consecutive)

            # 理想的连续工作天数是3-5天
            if 3 <= max_consecutive <= 5:
                continuity_score += 1
            elif max_consecutive < 3:
                continuity_score += max_consecutive / 3
            else:  # max_consecutive > 5
                continuity_score += 5 / max_consecutive

        return continuity_score / total_caregivers

    def evaluate_non_sleep_activity(self, schedule):
        """评估非睡眠活动的比例

        参考原接口，奖励非睡眠活动，使排班方案更加多样化

        Args:
            schedule: 排班方案

        Returns:
            非睡眠活动分数 (0-1)
        """
        if (
            "time_slot_assignments" not in schedule
            or not schedule["time_slot_assignments"]
        ):
            return 0

        total_slots = len(schedule["time_slot_assignments"])
        if total_slots == 0:
            return 0

        # 统计非睡眠活动的数量
        non_sleep_count = 0
        for slot in schedule["time_slot_assignments"]:
            activity_id = (
                int(slot.activity_id)
                if hasattr(slot, "activity_id")
                and slot.activity_id
                and slot.activity_id.isdigit()
                else 0
            )
            # 假设活动ID为10的是睡眠活动（参考原接口）
            if activity_id != 10:
                non_sleep_count += 1

        # 计算非睡眠活动的比例
        non_sleep_ratio = non_sleep_count / total_slots

        return non_sleep_ratio

    def evaluate_activity_diversity(self, schedule):
        """评估活动多样性

        参考原接口，奖励活动多样性，避免排班方案中的活动过于单一

        Args:
            schedule: 排班方案

        Returns:
            活动多样性分数 (0-1)
        """
        if (
            "time_slot_assignments" not in schedule
            or not schedule["time_slot_assignments"]
        ):
            return 0

        total_slots = len(schedule["time_slot_assignments"])
        if total_slots <= 1:
            return 0

        # 统计活动类型的数量
        activity_types = set()
        for slot in schedule["time_slot_assignments"]:
            activity_id = slot.activity_id if hasattr(slot, "activity_id") else "0"
            activity_types.add(activity_id)

        # 计算活动多样性分数
        # 活动类型越多，多样性越高，但有上限
        diversity_score = min(1.0, len(activity_types) / min(20, total_slots))

        return diversity_score

    def select_parents(self, population, fitness_values):
        """选择父代

        Args:
            population: 种群
            fitness_values: 适应度分数

        Returns:
            选中的父代
        """
        # 使用轮盘赋值选择
        total_fitness = sum(fitness_values)
        if total_fitness == 0:
            # 如果所有适应度都为0，则随机选择
            return random.sample(population, len(population) // 2)

        selection_probs = [f / total_fitness for f in fitness_values]
        selected_indices = random.choices(
            range(len(population)), weights=selection_probs, k=len(population) // 2
        )
        return [population[i] for i in selected_indices]

    def crossover(self, parent1, parent2):
        """交叉操作

        Args:
            parent1: 父代一
            parent2: 父代二

        Returns:
            两个子代
        """
        # 对班次分配进行交叉
        if "shift_assignments" in parent1 and "shift_assignments" in parent2:
            # 随机选择交叉点
            crossover_point = random.randint(
                1,
                min(
                    len(parent1["shift_assignments"]), len(parent2["shift_assignments"])
                )
                - 1,
            )

            # 创建子代
            child1 = {
                "shift_assignments": parent1["shift_assignments"][:crossover_point]
                + parent2["shift_assignments"][crossover_point:],
                "elder_schedules": parent1["elder_schedules"].copy(),
                "time_slot_assignments": (
                    parent1["time_slot_assignments"].copy()
                    if "time_slot_assignments" in parent1
                    else []
                ),
            }

            child2 = {
                "shift_assignments": parent2["shift_assignments"][:crossover_point]
                + parent1["shift_assignments"][crossover_point:],
                "elder_schedules": parent2["elder_schedules"].copy(),
                "time_slot_assignments": (
                    parent2["time_slot_assignments"].copy()
                    if "time_slot_assignments" in parent2
                    else []
                ),
            }

            return child1, child2

        # 如果没有班次分配，直接返回父代
        return parent1, parent2

    def mutate(self, schedule, caregivers):
        """变异操作

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            变异后的排班方案
        """
        # 深拷贝排班方案
        mutated = {
            "shift_assignments": schedule["shift_assignments"].copy(),
            "elder_schedules": {
                k: v.copy() for k, v in schedule["elder_schedules"].items()
            },
            "time_slot_assignments": (
                schedule["time_slot_assignments"].copy()
                if "time_slot_assignments" in schedule
                else []
            ),
        }

        # 变异班次分配
        if mutated["shift_assignments"]:
            # 随机选择一个班次分配进行变异
            idx = random.randint(0, len(mutated["shift_assignments"]) - 1)

            # 随机选择一个新的护理员
            new_caregiver = random.choice(caregivers)
            mutated["shift_assignments"][idx].caregiver_id = new_caregiver.id
            mutated["shift_assignments"][
                idx
            ].caregiver_name = new_caregiver.attendant_name

        return mutated

    def simulated_annealing(self, schedule, caregivers):
        """模拟退火优化

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        current = schedule
        current_fitness = self.evaluate_schedule(current, caregivers)
        best_schedule = current
        best_fitness = current_fitness

        # 设置最大温度
        max_temperature = self.initial_temperature * 10

        # 进行多次尝试
        for _ in range(10):  # 限制尝试次数
            # 生成领域解
            neighbor = self.mutate(current, caregivers)
            neighbor_fitness = self.evaluate_schedule(neighbor, caregivers)

            # 计算适应度差异
            delta = neighbor_fitness - current_fitness

            # 如果领域解更好，或者满足模拟退火接受条件，则接受领域解
            if delta > 0 or random.random() < math.exp(
                delta / max(self.temperature, 0.01)
            ):
                current = neighbor
                current_fitness = neighbor_fitness

                # 如果发现更好的解，更新最佳解
                if current_fitness > best_fitness:
                    best_schedule = current
                    best_fitness = current_fitness

        # 确保温度不超过最大值
        self.temperature = min(self.temperature, max_temperature)

        return best_schedule

    def generate_daily_schedule(
        self, target_date, caregivers, elders, shift_start_time=None
    ):
        """生成单日排班，同时考虑老人需求和护理员技能

        改进的算法，实现轮班制：
        1. 确保每个班次都至少有一个护理员
        2. 允许同一个护理员在同一天内担任多个班次，但要确保有足够的休息时间
        3. 保留预留资源的概念，但不影响基本的班次覆盖
        """
        # 如果提供了开始时间，调整班次时间
        current_shift_config = self.adjust_shift_times(shift_start_time)
        self.logger.info(f"班次时间配置: {current_shift_config}")

        # 获取当前启用的班次
        active_shifts = [
            shift
            for shift in self.shift_control["enabled_shifts"]
            if shift in current_shift_config
        ]

        if not active_shifts:
            self.logger.warning("没有启用的班次，无法生成排班")
            return {"shift_assignments": [], "schedule_results": [], "time_slots": []}

        self.logger.info(f"当前启用的班次: {active_shifts}")

        # 计算各班次所需人数
        required_caregivers = self.calculate_required_caregivers(len(caregivers))
        self.logger.info(f"各班次所需护理员数量: {required_caregivers}")

        # 检查是否需要启用轮班模式
        total_required = sum(required_caregivers.values())
        is_rotation_mode = total_required > len(caregivers)

        if is_rotation_mode:
            self.logger.info(
                f"所需护理员总数 {total_required} 超过可用护理员数量 {len(caregivers)}，启用轮班模式"
            )

        # 根据排班次数排序护理员，优先分配排班次数少的护理员
        # 这样可以确保预留资源不会总是同一个人
        if hasattr(self, "_caregiver_assignment_count"):
            sorted_caregivers = sorted(
                caregivers, key=lambda c: self._caregiver_assignment_count.get(c.id, 0)
            )
        else:
            # 如果还没有跟踪数据，则随机排序
            sorted_caregivers = list(caregivers)
            random.shuffle(sorted_caregivers)

        # 跟踪已分配班次的护理员，确保同一天不会分配过多班次
        assigned_caregivers = {}

        # 班次分配结果
        shift_assignments = []

        # 为每个班次分配护理员
        # 只为启用的班次分配护理员
        shift_types = active_shifts.copy()
        # 根据 order 字段排序
        shift_types.sort(key=lambda x: self.shift_config[x]["order"])
        for shift_type in shift_types:
            num_required = required_caregivers[shift_type]
            # 获取中文班次名称
            shift_name_cn = self.shift_config[shift_type]["name"]
            self.logger.info(f"开始为 {shift_name_cn} 分配 {num_required} 个护理员")

            # 获取班次时间
            shift_start = self.parse_time(
                current_shift_config[shift_type]["start_time"]
            )
            shift_end = self.parse_time(current_shift_config[shift_type]["end_time"])

            # 处理夜班跨天情况
            is_overnight = False
            if shift_type == "night_shift" and shift_end < shift_start:
                is_overnight = True
                self.logger.info(f"夜班是跨天班次: {shift_start} - {shift_end}")

            # 分配护理员到这个班次
            assigned_count = 0

            # 如果在轮班模式下，我们需要确保每个班次至少有一个人
            if is_rotation_mode and num_required > 0:
                # 在轮班模式下，我们需要找到最适合这个班次的护理员
                # 优先考虑还没有被分配班次的护理员
                available_caregivers = [
                    c for c in sorted_caregivers if c.id not in assigned_caregivers
                ]

                # 如果没有可用的护理员，则考虑已经被分配了一个班次的护理员
                if not available_caregivers:
                    available_caregivers = [
                        c
                        for c in sorted_caregivers
                        if assigned_caregivers.get(c.id, 0) < 2
                    ]

                # 如果还是没有可用的护理员，则使用所有护理员
                if not available_caregivers:
                    available_caregivers = sorted_caregivers

                # 选择第一个可用的护理员
                if available_caregivers:
                    caregiver = available_caregivers[0]

                    # 更新已分配班次计数
                    assigned_caregivers[caregiver.id] = (
                        assigned_caregivers.get(caregiver.id, 0) + 1
                    )

                    # 获取中文班次名称
                    shift_name_cn = self.shift_config[shift_type]["name"]

                    # 创建班次分配记录
                    assignment = ShiftAssignment(
                        id=str(uuid.uuid4()),
                        caregiver_id=caregiver.id,
                        caregiver_name=caregiver.attendant_name,
                        shift_date=target_date,
                        shift_type=shift_type,  # 使用完整的班次名称，而不是中文名称
                        shift_start_time=shift_start,
                        shift_end_time=shift_end,
                        schedule_type="daily",
                        # created_at 和 updated_at 字段有默认值，不需要显式设置
                    )

                    shift_assignments.append(assignment)
                    assigned_count += 1
                    self.logger.info(
                        f"轮班模式: 分配护理员 {caregiver.attendant_name} 到 {shift_name_cn}，时间 {shift_start}-{shift_end}{' (跨天)' if is_overnight else ''}"
                    )
            else:
                # 正常模式，为这个班次分配指定数量的护理员
                for _ in range(num_required):
                    # 找到还没有被分配班次的护理员
                    available_caregivers = [
                        c for c in sorted_caregivers if c.id not in assigned_caregivers
                    ]

                    if available_caregivers:
                        caregiver = available_caregivers[0]

                        # 标记该护理员已分配班次
                        assigned_caregivers[caregiver.id] = 1

                        # 获取中文班次名称
                        shift_name_cn = self.shift_config[shift_type]["name"]

                        # 创建班次分配记录
                        assignment = ShiftAssignment(
                            id=str(uuid.uuid4()),
                            caregiver_id=caregiver.id,
                            caregiver_name=caregiver.attendant_name,
                            shift_date=target_date,
                            shift_type=shift_type,  # 使用完整的班次名称，而不是中文名称
                            shift_start_time=shift_start,
                            shift_end_time=shift_end,
                            schedule_type="daily",
                            # created_at 和 updated_at 字段有默认值，不需要显式设置
                        )

                        shift_assignments.append(assignment)
                        assigned_count += 1
                        self.logger.info(
                            f"分配护理员 {caregiver.attendant_name} 到 {shift_name_cn}，时间 {shift_start}-{shift_end}{' (跨天)' if is_overnight else ''}"
                        )

            if assigned_count < num_required:
                self.logger.warning(
                    f"{shift_name_cn} 实际分配了 {assigned_count} 个护理员，少于需求的 {num_required} 个"
                )

        # 根据老人需求和护理员技能生成详细的时间段安排
        elder_schedules = {}
        time_slot_assignments = []

        # 为每个老人生成排班
        for elder in elders:
            elder_id = elder.elder

            # 不清除已有数据，而是每次生成新的数据
            # 记录日志，显示当前生成的是新数据
            self.logger.info(f"为老人 {elder_id} 在 {target_date} 生成新的排班计划")

            # 评估老人的照护需求级别
            care_level = self.evaluate_care_needs(elder_id)
            self.logger.info(f"老人 {elder_id} 的照护需求级别为 {care_level}")

            # 创建排班结果记录
            # 初始化为空列表，后面会添加时间段条目
            schedule_entries = []

            # 创建排班结果对象，使用当前时间作为时间戳
            current_datetime = datetime.now()

            # 初始化与原接口格式一致的时间段条目列表
            # 预先创建self.time_slots_per_day个时间段（默认为72个，每段20分钟），默认为睡眠活动
            initial_schedule_entries = []
            self.logger.info(
                f"为老人 {elder_id} 创建 {self.time_slots_per_day} 个时间段，每段 {self.time_interval_minutes} 分钟"
            )

            # 调用封装的方法创建初始时间段
            initial_schedule_entries = self._create_initial_time_slots()

            # 创建新的排班结果对象，不检查是否已存在相同老人同一天的记录
            schedule_result_id = str(uuid.uuid4())
            self.logger.info(
                f"创建排班结果: {schedule_result_id}, 老人: {elder_id}, 日期: {current_datetime}"
            )

            # 获取下一个批次号
            batch_number = self.get_next_batch_number()

            schedule_result = ScheduleResult(
                id=schedule_result_id,
                elder=elder_id,
                schedule_date=current_datetime,  # 使用当前时间，包含时分秒
                schedule_data=json.dumps(
                    initial_schedule_entries
                ),  # 初始化为默认的时间段条目列表，转换为JSON字符串
                # 不使用不存在的字段
                # 在注释中记录信息，而不是使用不存在的字段
                plan_date=target_date,  # 使用目标日期作为排班日期
                batch_number=batch_number,  # 使用批次号
                create_time=current_datetime,  # 创建时间
                update_time=current_datetime,  # 更新时间
                status="active",  # 状态
            )

            # 记录日志
            self.logger.info(
                f"创建排班结果: {schedule_result.id}, 老人: {elder_id}, 日期: {schedule_result.schedule_date}"
            )

            # 确保排班结果对象被添加到elder_schedules字典中
            elder_schedules[elder_id] = {
                "schedule_result": schedule_result,
                "time_slots": [],
            }

            # 根据老人的照护需求级别获取适合的活动
            suitable_activities = self.get_activities_by_care_level(
                elder_id, care_level
            )
            self.logger.info(
                f"为老人 {elder_id} 的照护需求级别 {care_level} 获取到 {len(suitable_activities)} 个适合的活动"
            )

            # 将适合的活动转换为逗号分隔的字符串，与原接口格式保持一致
            elder_actions = (
                ",".join(map(str, suitable_activities))
                if suitable_activities
                else elder.actions
            )

            # 如果没有适合的活动，使用老人原有的活动
            if not elder_actions:
                elder_actions = elder.actions
                self.logger.warning(
                    f"没有为老人 {elder_id} 找到适合的活动，使用原有活动: {elder_actions}"
                )

            # 为每个时间段分配护理员和活动
            daily_slots = []
            # 创建与原接口格式一致的时间段条目列表
            schedule_entries = [None] * self.time_slots_per_day

            for time_slot in range(self.time_slots_per_day):
                # 计算实际时间
                hours = (time_slot * self.time_interval_minutes) // 60
                minutes = (time_slot * self.time_interval_minutes) % 60
                end_hours = ((time_slot + 1) * self.time_interval_minutes) // 60
                end_minutes = ((time_slot + 1) * self.time_interval_minutes) % 60

                # 处理跨天的情况
                is_overnight = False
                if end_hours >= 24:
                    is_overnight = True
                    display_end_hours = end_hours - 24
                else:
                    display_end_hours = end_hours

                time_str = f"{hours:02d}:{minutes:02d}"
                time_slot_str = f"{hours:02d}:{minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}"

                # 记录日志
                log_message = f"时间段: {time_slot_str}"
                if is_overnight:
                    log_message += " (跨天)"
                self.logger.debug(log_message)

                # 找到当前时间段对应的班次和可用护理员
                current_shift = None
                current_time = self.parse_time(time_str)
                self.logger.info(f"检查时间段 {time_str} 对应的班次")

                # 只检查启用的班次
                for shift_type in active_shifts:
                    # 检查班次是否在当前班次配置中
                    if shift_type not in current_shift_config:
                        self.logger.warning(
                            f"班次 {shift_type} 不在当前班次配置中，跳过"
                        )
                        continue

                    shift_start = self.parse_time(
                        current_shift_config[shift_type]["start_time"]
                    )
                    shift_end = self.parse_time(
                        current_shift_config[shift_type]["end_time"]
                    )

                    # 处理跨天情况
                    if shift_end < shift_start:  # 跨天班次
                        # 跨天班次：如果当前时间小于结束时间或大于等于开始时间，则在该班次内
                        if current_time < shift_end or current_time >= shift_start:
                            current_shift = shift_type
                            self.logger.info(
                                f"时间 {time_str} 匹配{shift_type}(跨天): {shift_start}-{shift_end}"
                            )
                            break
                    else:
                        # 普通情况：如果当前时间在班次时间范围内，则匹配
                        if shift_start <= current_time < shift_end:
                            current_shift = shift_type
                            self.logger.info(
                                f"时间 {time_str} 匹配{shift_type}: {shift_start}-{shift_end}"
                            )
                            break

                # 时间段字符串已经在前面计算好了，这里不需要重复计算

                if not current_shift:
                    self.logger.warning(
                        f"时间 {time_str} 不在任何班次内，设置为睡眠活动"
                    )
                    # 如果不在任何班次内，创建一个睡眠活动的条目
                    entry = self.create_schedule_entry(
                        time_str=time_slot_str,
                        activity_name="睡眠",
                        activity_id="10",
                        caregiver_name="None",
                        caregiver_id="0",
                    )
                    schedule_entries[time_slot] = entry
                    continue

                # 找到当前班次的护理员
                # 使用完整的班次名称
                shift_caregivers = [
                    a for a in shift_assignments if a.shift_type == current_shift
                ]
                available_caregivers = []

                for assignment in shift_caregivers:
                    caregiver = next(
                        (c for c in caregivers if c.id == assignment.caregiver_id), None
                    )
                    if caregiver and self.check_caregiver_availability(
                        caregiver.id, target_date, time_slot
                    ):
                        available_caregivers.append(caregiver)

                # 根据老人需求匹配最合适的护理员
                matched_caregiver = self.match_caregiver_to_elder_needs(
                    available_caregivers, elder_actions
                )

                # 如果没有匹配的护理员，但有可用的护理员，则随机选择一个
                if not matched_caregiver and available_caregivers:
                    matched_caregiver = random.choice(available_caregivers)
                    self.logger.info(
                        f"在generate_care_timeline中随机选择护理员 {matched_caregiver.attendant_name}"
                    )
                # 如果没有可用的护理员，则从所有护理员中随机选择一个
                elif not matched_caregiver and caregivers:
                    matched_caregiver = random.choice(caregivers)
                    self.logger.warning(
                        f"没有可用的护理员，随机选择一个护理员: {matched_caregiver.attendant_name}"
                    )

                # 如果有护理员（匹配的或随机选择的）
                if matched_caregiver:
                    # 从老人需求中选择一个护理动作
                    action_ids = self.parse_skills(elder_actions)
                    caregiver_skills = self.parse_skills(matched_caregiver.skills)

                    # 获取老人的照护需求级别
                    care_level = self.evaluate_care_needs(elder.elder)

                    # 使用活动调度器选择最适合当前时间段的活动
                    # 首先过滤出护理员能够执行的活动
                    suitable_actions = [
                        action for action in action_ids if action in caregiver_skills
                    ]

                    # 如果没有匹配的活动，使用所有活动
                    if not suitable_actions:
                        suitable_actions = action_ids
                        self.logger.warning(
                            f"护理员 {matched_caregiver.attendant_name} 没有匹配的活动技能，使用所有活动"
                        )

                    # 检查是否是凤凰或深夜时间段
                    hour = int(time_slot_str.split(":")[0])
                    minute = int(time_slot_str.split(":")[1].split("-")[0])
                    hour_decimal = hour + minute / 60

                    # 检查是否是睡眠时间
                    is_sleep_time = False
                    for (
                        start,
                        end,
                    ), activities in (
                        self.activity_scheduler.fixed_time_activities.items()
                    ):
                        if any(
                            act_type == self.activity_scheduler.SLEEP
                            for act_type, _ in activities
                        ):
                            # 检查时间是否在范围内
                            if start < end:  # 不跨天
                                if start <= hour_decimal < end:
                                    is_sleep_time = True
                                    break
                            else:  # 跨天
                                if hour_decimal >= start or hour_decimal < end:
                                    is_sleep_time = True
                                    break

                    if is_sleep_time:
                        # 睡眠时间段强制安排睡眠活动
                        selected_action_id = "10"  # 睡眠活动ID为10
                        action_name = "睡眠"  # 直接设置活动名称为睡眠
                        self.logger.info(f"睡眠时间段 {time_slot_str} 强制安排睡眠活动")
                    else:
                        # 检查是否是用餐时间段
                        is_meal_time = False
                        for (
                            start,
                            end,
                        ), activities in (
                            self.activity_scheduler.fixed_time_activities.items()
                        ):
                            if any(
                                act_type == self.activity_scheduler.MEAL
                                for act_type, _ in activities
                            ):
                                # 检查时间是否在范围内
                                if start < end:  # 不跨天
                                    if start <= hour_decimal < end:
                                        is_meal_time = True
                                        break
                                else:  # 跨天
                                    if hour_decimal >= start or hour_decimal < end:
                                        is_meal_time = True
                                        break

                        if is_meal_time:
                            # 用餐时间段优先安排用餐活动
                            meal_activities = [
                                activity
                                for activity in suitable_actions
                                if self.activity_scheduler.get_activity_type(activity)
                                == self.activity_scheduler.MEAL
                            ]
                            if meal_activities:
                                selected_action_id = meal_activities[0]
                                self.logger.info(
                                    f"用餐时间段 {time_slot_str} 安排用餐活动 {selected_action_id}"
                                )
                            else:
                                # 使用活动调度器选择最适合的活动
                                selected_action_id = (
                                    self.activity_scheduler.get_suitable_activity(
                                        suitable_actions, time_slot_str, care_level
                                    )
                                )
                        else:
                            # 使用活动调度器选择最适合的活动
                            selected_action_id = (
                                self.activity_scheduler.get_suitable_activity(
                                    suitable_actions, time_slot_str, care_level
                                )
                            )

                    # 检查活动连续性
                    if time_slot > 0 and selected_action_id:
                        # 获取前一个时间段的活动
                        prev_time_slot = time_slot - 1
                        if prev_time_slot in schedule_entries:
                            prev_entry = schedule_entries[prev_time_slot]
                            prev_activity_id = prev_entry.get("ActivityId")

                            # 检查活动连续性
                            is_continuous = self.continuity_checker.check_continuity(
                                prev_activity_id, selected_action_id
                            )

                            # 如果活动不连续，尝试选择更合适的活动
                            if (
                                not is_continuous
                                and not is_sleep_time
                                and not is_meal_time
                            ):
                                # 根据前一个活动建议下一个活动
                                suggested_action_id = (
                                    self.continuity_checker.suggest_next_activity(
                                        prev_activity_id, suitable_actions
                                    )
                                )
                                if suggested_action_id:
                                    selected_action_id = suggested_action_id
                                    self.logger.info(
                                        f"根据活动连续性调整活动: {prev_activity_id} -> {selected_action_id}"
                                    )

                    # 如果没有选择到活动，随机选择一个
                    if not selected_action_id and action_ids:
                        selected_action_id = random.choice(action_ids)
                        self.logger.warning(
                            f"活动调度器没有选择到活动，随机选择一个: {selected_action_id}"
                        )

                    if selected_action_id:
                        # 获取护理动作详情
                        nursing_actions = self.get_nursing_actions()

                        # 尝试不同的格式获取活动
                        action = None
                        if selected_action_id in nursing_actions:
                            action = nursing_actions[selected_action_id]
                        elif str(selected_action_id) in nursing_actions:
                            action = nursing_actions[str(selected_action_id)]

                        # 如果找到了活动，使用其名称
                        if action and hasattr(action, "name") and action.name:
                            action_name = action.name
                        else:
                            # 如果找不到活动，根据活动ID设置默认名称
                            if selected_action_id == 10 or selected_action_id == "10":
                                action_name = "睡眠"
                            elif selected_action_id == 8 or selected_action_id == "8":
                                action_name = "日常生活"
                            else:
                                action_name = f"活动{selected_action_id}"
                            self.logger.warning(
                                f"找不到活动ID {selected_action_id} 的详情，使用默认名称: {action_name}"
                            )

                        # 创建时间段记录，确保包含完整的日期时间信息
                        current_time = datetime.now()  # 使用当前时间，包含年月日时分秒
                        time_slot_record = TimeSlot(
                            id=str(uuid.uuid4()),
                            schedule_result_id=schedule_result.id,
                            elder=elder.elder,
                            time_slot=time_slot_str,  # 使用完整的时间段格式
                            activity=action_name,
                            activity_id=str(selected_action_id),
                            caregiver=matched_caregiver.attendant_name,
                            caregiver_id=matched_caregiver.id,
                            time_order=time_slot,
                            schedule_date=current_time,  # 使用当前时间，包含年月日时分秒
                            plan_date=target_date,  # 使用目标日期作为排班日期
                            batch_number=schedule_result.batch_number,  # 使用与排班结果相同的批次号
                            create_time=current_time,  # 创建时间
                            update_time=current_time,  # 更新时间
                            status="active",  # 状态
                        )

                        # 记录日志
                        self.logger.debug(
                            f"创建时间段记录: {time_slot_str}, 时间戳: {current_time}"
                        )

                        # 记录日志
                        self.logger.info(
                            f"创建时间段: 老人 {elder.elder}, 护理员 {matched_caregiver.attendant_name}, 时间 {time_slot_str}, 活动 {action_name}"
                        )

                        # 添加到列表中
                        daily_slots.append(time_slot_record)
                        time_slot_assignments.append(time_slot_record)

                        # 添加到老人的时间段列表中
                        if elder.elder in elder_schedules:
                            elder_schedules[elder.elder]["time_slots"].append(
                                time_slot_record
                            )

                        # 更新护理员可用性
                        self.update_caregiver_availability(
                            matched_caregiver.id, target_date, time_slot, False
                        )

                        # 创建与原接口格式一致的时间段条目
                        entry = self.create_schedule_entry(
                            time_str=time_slot_str,
                            activity_name=action_name,
                            activity_id=str(selected_action_id),
                            caregiver_name=matched_caregiver.attendant_name,
                            caregiver_id=matched_caregiver.id,
                        )
                    else:
                        # 如果没有选择的动作，创建一个睡眠活动的条目
                        entry = self.create_schedule_entry(
                            time_str=time_slot_str,
                            activity_name="睡眠",
                            activity_id="10",
                            caregiver_name="None",
                            caregiver_id="0",
                        )
                else:
                    # 如果没有匹配的护理员，创建一个睡眠活动的条目
                    entry = self.create_schedule_entry(
                        time_str=time_slot_str,
                        activity_name="睡眠",
                        activity_id="10",
                        caregiver_name="None",
                        caregiver_id="0",
                    )

                # 添加到时间段条目列表中
                schedule_entries[time_slot] = entry

            # 确保所有时间段都有条目，将None替换为睡眠活动
            for time_slot in range(self.time_slots_per_day):
                if schedule_entries[time_slot] is None:
                    # 计算实际时间
                    hours = (time_slot * self.time_interval_minutes) // 60
                    minutes = (time_slot * self.time_interval_minutes) % 60

                    # 计算结束时间
                    end_minutes = minutes + self.time_interval_minutes
                    end_hours = hours
                    if end_minutes >= 60:
                        end_minutes -= 60
                        end_hours += 1
                        if end_hours >= 24:
                            end_hours -= 24

                    # 格式化时间段字符串
                    time_slot_str = (
                        f"{hours:02d}:{minutes:02d}-{end_hours:02d}:{end_minutes:02d}"
                    )

                    # 创建睡眠活动的条目
                    schedule_entries[time_slot] = self.create_schedule_entry(
                        time_str=time_slot_str,
                        activity_name="睡眠",
                        activity_id="10",
                        caregiver_name="None",
                        caregiver_id="0",
                    )

            # 确保所有时间段都有条目，将None替换为睡眠活动
            for time_slot in range(self.time_slots_per_day):
                if schedule_entries[time_slot] is None:
                    # 计算实际时间
                    hours = (time_slot * self.time_interval_minutes) // 60
                    minutes = (time_slot * self.time_interval_minutes) % 60
                    end_hours = ((time_slot + 1) * self.time_interval_minutes) // 60
                    end_minutes = ((time_slot + 1) * self.time_interval_minutes) % 60

                    # 处理跨天的情况
                    is_overnight = False
                    if end_hours >= 24:
                        is_overnight = True
                        display_end_hours = end_hours - 24
                    else:
                        display_end_hours = end_hours

                    # 格式化时间段字符串
                    time_slot_str = f"{hours:02d}:{minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}"

                    # 记录日志
                    log_message = f"时间段: {time_slot_str}"
                    if is_overnight:
                        log_message += " (跨天)"
                    self.logger.debug(log_message)

                    # 创建睡眠活动的条目
                    schedule_entries[time_slot] = self.create_schedule_entry(
                        time_str=time_slot_str,
                        activity_name="睡眠",
                        activity_id="10",
                        caregiver_name="None",
                        caregiver_id="0",
                    )

            # 转换为列表并按时间排序
            schedule_entries = [
                entry for entry in schedule_entries if entry is not None
            ]

            # 按时间排序
            schedule_entries.sort(key=lambda x: x["TimeSlot"])

            # 更新排班结果的JSON数据
            if elder.elder in elder_schedules:
                schedule_result = elder_schedules[elder.elder]["schedule_result"]

                # 使用辅助方法验证和修复排班数据
                schedule_entries = self._validate_and_fix_schedule_data(
                    schedule_entries
                )

                # 更新排班结果的数据，转换为JSON字符串
                schedule_result.schedule_data = json.dumps(schedule_entries)

                # 记录日志
                self.logger.info(
                    f"更新老人 {elder.elder} 的排班结果，包含 {len(schedule_entries)} 个时间段条目"
                )

                # 确保时间段列表已经添加到elder_schedules字典中
                self.logger.info(
                    f"老人 {elder.elder} 的排班结果包含 {len(elder_schedules[elder.elder]['time_slots'])} 个时间段和 {len(schedule_entries)} 个时间段条目"
                )

        return {
            "shift_assignments": shift_assignments,
            "elder_schedules": elder_schedules,
            "time_slot_assignments": time_slot_assignments,
        }

    def generate_schedule(
        self, schedule_type="daily", num_days=1, start_date=None, shift_start_time=None
    ):
        """生成排班计划

        参数:
            schedule_type: 排班类型（'daily', 'weekly', 'monthly', 'quarterly', 'yearly'）
            num_days: 当选择daily时，指定天数
            start_date: 开始日期，默认为今天
            shift_start_time: 班次开始时间，格式为'HH:MM'
        """
        if not start_date:
            start_date = date.today()
        elif isinstance(start_date, str):
            start_date = datetime.strptime(start_date, "%Y-%m-%d").date()

        # 根据排班类型确定结束日期
        if schedule_type == "daily":
            end_date = start_date + timedelta(days=num_days - 1)
        elif schedule_type == "weekly":
            end_date = start_date + timedelta(days=6)  # 一周7天
        elif schedule_type == "monthly":
            # 计算下个月的同一天
            if start_date.month == 12:
                end_date = date(start_date.year + 1, 1, start_date.day)
            else:
                # 处理月末日期问题
                next_month = start_date.month + 1
                last_day = 31  # 默认最大天数
                while True:
                    try:
                        end_date = date(start_date.year, next_month, last_day)
                        break
                    except ValueError:
                        last_day -= 1
        elif schedule_type == "quarterly":
            # 计算三个月后的同一天
            month = start_date.month + 3
            year = start_date.year
            if month > 12:
                month -= 12
                year += 1
            # 处理月末日期问题
            last_day = 31  # 默认最大天数
            while True:
                try:
                    end_date = date(year, month, last_day)
                    break
                except ValueError:
                    last_day -= 1
        elif schedule_type == "yearly":
            end_date = date(
                start_date.year + 1, start_date.month, start_date.day
            ) - timedelta(days=1)
        else:
            raise ValueError(f"不支持的排班类型: {schedule_type}")

        # 获取所有护理员和需要安排的老人
        all_caregivers = self.get_caregivers()
        all_elders = self.get_elders()

        if not all_caregivers:
            raise ValueError("没有可用的护理员")

        if not all_elders:
            raise ValueError("没有需要安排的老人")

        # 生成每一天的排班
        all_results = {
            "shift_assignments": [],  # 班次分配
            "schedule_results": [],  # 排班结果
            "time_slots": [],  # 时间段分配
            "elder_schedules": {},  # 老人排班计划，用于中间处理
        }

        current_date = start_date

        # 初始化或获取护理员排班次数跟踪器
        if not hasattr(self, "_caregiver_assignment_count"):
            self._caregiver_assignment_count = {
                caregiver.id: 0 for caregiver in all_caregivers
            }
            self.logger.info(
                f"初始化护理员排班计数: {self._caregiver_assignment_count}"
            )

        # 跟踪每日排班的护理员，实现轮班制
        while current_date <= end_date:
            self.logger.info(f"开始生成 {current_date} 的排班计划")
            self.logger.info(f"当前护理员排班次数: {self._caregiver_assignment_count}")

            # 生成当天的排班
            daily_results = self.generate_daily_schedule(
                current_date,
                all_caregivers,  # 传入所有护理员，在方法内部会根据排班次数排序
                all_elders,
                shift_start_time,
            )

            # 更新护理员排班次数
            for assignment in daily_results["shift_assignments"]:
                caregiver_id = assignment.caregiver_id
                self._caregiver_assignment_count[caregiver_id] = (
                    self._caregiver_assignment_count.get(caregiver_id, 0) + 1
                )
                self.logger.info(
                    f"护理员 {assignment.caregiver_name} 排班次数增加到 {self._caregiver_assignment_count[caregiver_id]}"
                )

            # 合并结果
            all_results["shift_assignments"].extend(daily_results["shift_assignments"])

            # 添加老人排班结果
            for elder_id, elder_schedule in daily_results["elder_schedules"].items():
                # 添加排班结果和时间段
                all_results["schedule_results"].append(
                    elder_schedule["schedule_result"]
                )
                all_results["time_slots"].extend(elder_schedule["time_slots"])

                # 将老人排班计划存入elder_schedules字典，以便后续处理
                if elder_id not in all_results["elder_schedules"]:
                    all_results["elder_schedules"][elder_id] = {
                        "schedule_results": [],
                        "time_slots": [],
                    }

                all_results["elder_schedules"][elder_id]["schedule_results"].append(
                    elder_schedule["schedule_result"]
                )
                all_results["elder_schedules"][elder_id]["time_slots"].extend(
                    elder_schedule["time_slots"]
                )

            current_date += timedelta(days=1)

        # 输出最终的护理员排班统计
        self.logger.info("最终护理员排班统计:")
        for caregiver in all_caregivers:
            self.logger.info(
                f"护理员 {caregiver.attendant_name} (编号: {caregiver.id}) 排班次数: {self._caregiver_assignment_count[caregiver.id]}"
            )

        # 分析排班结果
        shift_counts = {"班次1": 0, "班次2": 0, "班次3": 0}
        for assignment in all_results["shift_assignments"]:
            if assignment.shift_type in shift_counts:
                shift_counts[assignment.shift_type] += 1

        self.logger.info(
            f"排班统计: 班次1 {shift_counts['班次1']} 人次, 班次2 {shift_counts['班次2']} 人次, 班次3 {shift_counts['班次3']} 人次"
        )

        return all_results

    def get_next_batch_number(self):
        """获取下一个批次号

        Returns:
            int: 下一个批次号
        """
        try:
            # 查询当前最大的批次号
            from sqlalchemy import func

            max_batch = db.session.query(func.max(ScheduleResult.batch_number)).scalar()

            # 如果没有记录，返回1，否则返回最大批次号+1
            if max_batch is None:
                return 1
            else:
                return max_batch + 1
        except Exception as e:
            self.logger.error(f"获取下一个批次号时出错: {str(e)}")
            # 如果出错，返回当前时间戳作为批次号
            import time

            return int(time.time())

    def save_shift_assignments(self, shift_assignments):
        """仅保存班次分配到数据库

        Args:
            shift_assignments: 班次分配列表

        Returns:
            bool: 是否保存成功
        """
        try:
            # 开始事务
            db.session.begin()

            # 保存班次分配到shift_assignments表
            for assignment in shift_assignments:
                db.session.add(assignment)

            # 提交事务
            db.session.commit()

            # 记录保存的数据
            self.logger.info("成功保存排班计划:")
            self.logger.info(
                f"  - {len(shift_assignments)} 个班次分配到shift_assignments表"
            )
            self.logger.info(
                "重要：护理员可用性数据仅在内存中跟踪，不写入caregiver_schedules表"
            )
            return True
        except Exception as e:
            db.session.rollback()
            self.logger.error(f"保存班次分配失败: {str(e)}")
            return False

    # 提供一个安全的事务上下文
    @staticmethod
    @contextmanager
    def safe_transaction(session):
        try:
            yield
            session.commit()
        except Exception:
            session.rollback()
            raise

    # 增强版的create_schedule_entry方法已合并到上面的create_schedule_entry方法中

    def save_schedule(self, schedule_results, target_date=None):
        """保存排班计划到数据库

        保存数据到以下表：
        - shift_assignments表：班次分配
        - schedule_results表：排班结果
        - time_slots表：时间段分配

        Args:
            schedule_results: 排班结果字典
            target_date: 目标日期，如果为None，则使用当前日期

        注意：不会向caregiver_schedules表写入数据
        """
        try:
            # 处理target_date参数
            if target_date is None:
                # 如果没有提供目标日期，使用当前日期
                from datetime import date

                target_date = date.today()
            elif isinstance(target_date, str):
                # 如果目标日期是字符串，转换为日期对象
                from datetime import datetime

                target_date = datetime.strptime(target_date, "%Y-%m-%d").date()

            self.logger.info(f"目标日期: {target_date}")

            # 使用安全的事务上下文
            with self.safe_transaction(db.session):
                # 1. 保存班次分配到shift_assignments表
                if schedule_results.get("shift_assignments"):
                    self.logger.info(
                        f"批量保存 {len(schedule_results['shift_assignments'])} 个班次分配"
                    )
                    db.session.bulk_save_objects(schedule_results["shift_assignments"])

                # 2. 保存排班结果到schedule_results表
                schedule_results_count = 0
                self.logger.info(
                    f"elder_schedules字典中有 {len(schedule_results.get('elder_schedules', {}))} 个老人"
                )
                for elder_name, elder_schedule in schedule_results.get(
                    "elder_schedules", {}
                ).items():
                    self.logger.info(f"处理老人 {elder_name} 的排班结果")

                    # 处理单个排班结果对象
                    if "schedule_result" in elder_schedule:
                        schedule_result = elder_schedule.get("schedule_result")
                        if schedule_result:
                            # 确保 schedule_data 是有效的数据
                            validated_data = self._validate_and_fix_schedule_data(
                                schedule_result.schedule_data
                            )

                            # 记录日志
                            self.logger.info(
                                f"验证和修复排班数据，共 {len(validated_data)} 个条目"
                            )

                            # 转换为JSON字符串
                            schedule_result.schedule_data = json.dumps(validated_data)

                            # 设置类型为三班制接口
                            schedule_result.schedule_type = 1

                            # 设置时间段数量
                            schedule_result.slots_count = len(validated_data)

                            self.logger.info(
                                f"添加排班结果: {schedule_result.id}, 老人: {schedule_result.elder}, 时间段数量: {schedule_result.slots_count}"
                            )
                            db.session.add(schedule_result)
                            schedule_results_count += 1
                        else:
                            self.logger.warning(f"老人 {elder_name} 的排班结果为None")
                            # 创建新的排班结果
                            import uuid
                            from datetime import datetime

                            # 创建与原接口格式一致的时间段条目列表
                            schedule_entries = [None] * self.time_slots_per_day
                            time_slots = elder_schedule.get("time_slots", [])

                            # 创建时间段字典，用于去重
                            time_slot_dict = {}

                            # 如果有时间段列表，则创建时间段条目
                            if time_slots:
                                for slot in time_slots:
                                    # 解析时间字符串，获取小时和分钟
                                    hours, minutes = map(int, slot.time_slot.split(":"))
                                    # 计算时间段索引，根据时间间隔动态计算
                                    time_index = hours * (
                                        60 // self.time_interval_minutes
                                    ) + (minutes // self.time_interval_minutes)

                                    # 确保索引在有效范围内
                                    if 0 <= time_index < self.time_slots_per_day:
                                        # 如果该时间段已经有条目，跳过
                                        if time_index in time_slot_dict:
                                            continue

                                        entry = self.create_schedule_entry(
                                            time_str=slot.time_slot,
                                            activity_name=slot.activity,
                                            activity_id=slot.activity_id,
                                            caregiver_name=slot.caregiver,
                                            caregiver_id=slot.caregiver_id,
                                        )
                                        schedule_entries[time_index] = entry
                                        time_slot_dict[time_index] = True

                            # 确保生成完整的48个时间段
                            # 填充空缺的时间段
                            for time_slot in range(self.time_slots_per_day):
                                # 如果这个时间段还没有条目，创建一个睡眠活动的条目
                                if schedule_entries[time_slot] is None:
                                    # 计算实际时间
                                    hours = (
                                        time_slot * self.time_interval_minutes
                                    ) // 60
                                    minutes = (
                                        time_slot * self.time_interval_minutes
                                    ) % 60
                                    end_hours = (
                                        (time_slot + 1) * self.time_interval_minutes
                                    ) // 60
                                    end_minutes = (
                                        (time_slot + 1) * self.time_interval_minutes
                                    ) % 60

                                    # 处理跨天的情况
                                    is_overnight = False
                                    if end_hours >= 24:
                                        is_overnight = True
                                        display_end_hours = end_hours - 24
                                    else:
                                        display_end_hours = end_hours

                                    time_str = f"{hours:02d}:{minutes:02d}-{display_end_hours:02d}:{end_minutes:02d}"

                                    # 记录日志
                                    log_message = f"时间段: {time_str}"
                                    if is_overnight:
                                        log_message += " (跨天)"
                                    self.logger.debug(log_message)

                                    entry = self.create_schedule_entry(
                                        time_str=time_str,
                                        activity_name="睡眠",
                                        activity_id="10",
                                        caregiver_name="None",
                                        caregiver_id="0",
                                    )
                                    schedule_entries[time_slot] = entry

                            # 按时间排序
                            schedule_entries.sort(key=lambda x: x["TimeSlot"])

                            # 创建排班结果对象，使用列表格式的schedule_data
                            # 确保每个时间段条目都有正确的格式
                            for entry in schedule_entries:
                                if not isinstance(entry, dict):
                                    continue
                                # 确保必要的字段存在
                                if "TimeSlot" not in entry:
                                    entry["TimeSlot"] = "00:00-00:30"
                                if "Activity" not in entry:
                                    entry["Activity"] = "睡眠"
                                if "ActivityId" not in entry:
                                    entry["ActivityId"] = "10"
                                if "Caregiver" not in entry:
                                    entry["Caregiver"] = "None"
                                if "CaregiverId" not in entry:
                                    entry["CaregiverId"] = "0"

                            # 检查是否已存在相同老人同一天的记录
                            today = datetime.now().date()
                            existing_result = (
                                ScheduleResult.query.filter(
                                    ScheduleResult.elder == elder_name,
                                    func.date(ScheduleResult.schedule_date) == today,
                                )
                                .order_by(ScheduleResult.schedule_date.desc())
                                .first()
                            )

                            if existing_result:
                                # 如果已存在记录，更新而不是创建新记录
                                self.logger.info(
                                    f"发现老人 {elder_name} 已有今天的排班结果，进行更新"
                                )
                                existing_result.schedule_date = (
                                    datetime.now()
                                )  # 更新时间戳

                                # 验证和修复排班数据
                                validated_data = self._validate_and_fix_schedule_data(
                                    schedule_entries
                                )

                                # 转换为JSON字符串
                                existing_result.schedule_data = json.dumps(
                                    validated_data
                                )  # 更新数据

                                # 不使用不存在的字段
                                # 在注释中记录信息，而不是使用不存在的字段
                                self.logger.info(
                                    f"该排班结果由三班制接口生成，包含 {len(validated_data)} 个时间段"
                                )

                                schedule_results_count += 1

                                # 更新elder_schedule中的schedule_result
                                elder_schedule["schedule_result"] = existing_result
                            else:
                                # 如果不存在，创建新的排班结果对象

                                # 验证和修复排班数据
                                validated_data = self._validate_and_fix_schedule_data(
                                    schedule_entries
                                )

                                current_time = datetime.now()
                                new_schedule_result = ScheduleResult(
                                    id=str(uuid.uuid4()),
                                    elder=elder_name,
                                    schedule_date=current_time,  # 使用当前时间，包含时分秒
                                    schedule_data=json.dumps(
                                        validated_data
                                    ),  # 转换为JSON字符串
                                    # 不使用不存在的字段
                                    # 在注释中记录信息，而不是使用不存在的字段
                                    create_time=current_time,  # 创建时间
                                    update_time=current_time,  # 更新时间
                                    status="active",  # 状态
                                )

                                self.logger.info(
                                    f"创建新的排班结果: {new_schedule_result.id}, 老人: {new_schedule_result.elder}"
                                )
                                db.session.add(new_schedule_result)
                                schedule_results_count += 1

                                # 更新elder_schedule中的schedule_result
                                elder_schedule["schedule_result"] = new_schedule_result

                    # 处理排班结果列表
                    elif "schedule_results" in elder_schedule:
                        schedule_results_list = elder_schedule.get(
                            "schedule_results", []
                        )
                        self.logger.info(
                            f"老人 {elder_name} 有 {len(schedule_results_list)} 个排班结果"
                        )

                        for schedule_result in schedule_results_list:
                            if schedule_result:
                                # 确保 schedule_data 是有效的数据
                                validated_data = self._validate_and_fix_schedule_data(
                                    schedule_result.schedule_data
                                )

                                # 记录日志
                                self.logger.info(
                                    f"验证和修复排班数据，共 {len(validated_data)} 个条目"
                                )

                                # 转换为JSON字符串
                                schedule_result.schedule_data = json.dumps(
                                    validated_data
                                )

                                # 不使用不存在的字段
                                # 在注释中记录信息，而不是使用不存在的字段
                                self.logger.info(
                                    f"该排班结果由三班制接口生成，包含 {len(validated_data)} 个时间段"
                                )

                                self.logger.info(
                                    f"添加排班结果: {schedule_result.id}, 老人: {schedule_result.elder}"
                                )
                                db.session.add(schedule_result)
                                schedule_results_count += 1
                            else:
                                self.logger.warning(
                                    f"老人 {elder_name} 的排班结果列表中有None元素"
                                )

                    # 既没有单个排班结果也没有排班结果列表
                    else:
                        self.logger.warning(f"老人 {elder_name} 的排班结果不存在")
                        # 创建新的排班结果
                        import uuid
                        from datetime import datetime

                        # 创建新的排班结果，使用与原接口一致的格式
                        # 首先检查是否有时间段列表
                        time_slots = elder_schedule.get("time_slots", [])

                        # 创建与原接口格式一致的时间段条目列表
                        schedule_entries = [None] * self.time_slots_per_day

                        # 创建时间段字典，用于去重
                        time_slot_dict = {}

                        # 如果有时间段列表，则创建时间段条目
                        if time_slots:
                            for slot in time_slots:
                                # 解析时间字符串，获取小时和分钟
                                hours, minutes = map(int, slot.time_slot.split(":"))
                                # 计算时间段索引，根据时间间隔动态计算
                                time_index = hours * (
                                    60 // self.time_interval_minutes
                                ) + (minutes // self.time_interval_minutes)

                                # 确保索引在有效范围内
                                if 0 <= time_index < self.time_slots_per_day:
                                    # 如果该时间段已经有条目，跳过
                                    if time_index in time_slot_dict:
                                        continue

                                    entry = self.create_schedule_entry(
                                        time_str=slot.time_slot,
                                        activity_name=slot.activity,
                                        activity_id=slot.activity_id,
                                        caregiver_name=slot.caregiver,
                                        caregiver_id=slot.caregiver_id,
                                    )
                                    schedule_entries[time_index] = entry
                                    time_slot_dict[time_index] = True

                        # 确保生成完整的时间段，数量由self.time_slots_per_day决定
                        # 填充空缺的时间段
                        for time_slot in range(self.time_slots_per_day):
                            # 如果这个时间段还没有条目，创建一个睡眠活动的条目
                            if schedule_entries[time_slot] is None:
                                # 计算实际时间
                                hours = (time_slot * self.time_interval_minutes) // 60
                                minutes = (time_slot * self.time_interval_minutes) % 60
                                time_str = f"{hours:02d}:{minutes:02d}"

                                entry = self.create_schedule_entry(
                                    time_str=time_str,
                                    activity_name="睡眠",
                                    activity_id="10",
                                    caregiver_name="None",
                                    caregiver_id="0",
                                )
                                schedule_entries[time_slot] = entry

                        # 按时间排序
                        schedule_entries.sort(key=lambda x: x["TimeSlot"])

                        # 创建排班结果对象
                        # 确保每个时间段条目都有正确的格式
                        for entry in schedule_entries:
                            if not isinstance(entry, dict):
                                continue
                            # 确保必要的字段存在
                            if "TimeSlot" not in entry:
                                entry["TimeSlot"] = "00:00-00:30"
                            if "Activity" not in entry:
                                entry["Activity"] = "睡眠"
                            if "ActivityId" not in entry:
                                entry["ActivityId"] = "10"
                            if "Caregiver" not in entry:
                                entry["Caregiver"] = "None"
                            if "CaregiverId" not in entry:
                                entry["CaregiverId"] = "0"

                        # 创建新的排班结果对象，不检查是否已存在相同老人同一天的记录
                        # 获取下一个批次号
                        batch_number = self.get_next_batch_number()
                        current_datetime = datetime.now()

                        # 解析目标日期
                        if isinstance(target_date, str):
                            from datetime import datetime

                            plan_date = datetime.strptime(
                                target_date, "%Y-%m-%d"
                            ).date()
                        else:
                            plan_date = target_date

                        # 验证和修复排班数据
                        validated_data = self._validate_and_fix_schedule_data(
                            schedule_entries
                        )

                        new_schedule_result = ScheduleResult(
                            id=str(uuid.uuid4()),
                            elder=elder_name,
                            schedule_date=current_datetime,  # 使用当前时间，包含时分秒
                            schedule_data=json.dumps(
                                validated_data
                            ),  # 转换为JSON字符串
                            # 不使用不存在的字段
                            # 在注释中记录信息，而不是使用不存在的字段
                            plan_date=plan_date,  # 使用目标日期作为排班日期
                            batch_number=batch_number,  # 使用批次号
                            create_time=current_datetime,  # 创建时间
                            update_time=current_datetime,  # 更新时间
                            status="active",  # 状态
                        )

                        self.logger.info(
                            f"创建新的排班结果: {new_schedule_result.id}, 老人: {new_schedule_result.elder}"
                        )
                        db.session.add(new_schedule_result)
                        schedule_results_count += 1

                        # 更新elder_schedule中的schedule_result
                        elder_schedule["schedule_result"] = new_schedule_result

                # 3. 保存时间段分配到time_slots表
                time_slots_count = 0
                time_slots_to_add = []  # 收集所有要添加的时间段，减少数据库查询次数

                for elder_name, elder_schedule in schedule_results.get(
                    "elder_schedules", {}
                ).items():
                    time_slots = elder_schedule.get("time_slots", [])
                    schedule_result = elder_schedule.get("schedule_result")

                    self.logger.info(f"处理 {len(time_slots)} 个时间段记录")

                    # 确保时间段与排班结果正确关联
                    for time_slot in time_slots:
                        try:
                            # 数据验证和清理
                            if not time_slot.time_slot or not isinstance(
                                time_slot.time_slot, str
                            ):
                                self.logger.warning(
                                    f"时间段无效: {time_slot.time_slot}"
                                )
                                continue

                            # 确保时间段格式正确
                            if ":" not in time_slot.time_slot:
                                self.logger.warning(
                                    f"时间段格式无效: {time_slot.time_slot}"
                                )
                                continue

                            # 确保活动信息存在
                            if not time_slot.activity:
                                time_slot.activity = "睡眠"

                            # 确保活动ID存在
                            if not time_slot.activity_id:
                                time_slot.activity_id = "10"

                            # 确保护理员信息存在
                            if not time_slot.caregiver:
                                time_slot.caregiver = "None"

                            # 确保护理员ID存在
                            if not time_slot.caregiver_id:
                                time_slot.caregiver_id = "0"

                            # 确保时间戳存在
                            from datetime import datetime

                            current_time = datetime.now()
                            if not time_slot.schedule_date:
                                time_slot.schedule_date = current_time

                            # 添加新字段
                            if (
                                not hasattr(time_slot, "plan_date")
                                or not time_slot.plan_date
                            ):
                                time_slot.plan_date = target_date

                            if (
                                not hasattr(time_slot, "batch_number")
                                or not time_slot.batch_number
                            ):
                                # 如果有排班结果，使用相同的批次号
                                if schedule_result and hasattr(
                                    schedule_result, "batch_number"
                                ):
                                    time_slot.batch_number = (
                                        schedule_result.batch_number
                                    )
                                else:
                                    # 否则获取一个新的批次号
                                    time_slot.batch_number = (
                                        self.get_next_batch_number()
                                    )

                            if (
                                not hasattr(time_slot, "create_time")
                                or not time_slot.create_time
                            ):
                                time_slot.create_time = current_time

                            if (
                                not hasattr(time_slot, "update_time")
                                or not time_slot.update_time
                            ):
                                time_slot.update_time = current_time

                            if not hasattr(time_slot, "status") or not time_slot.status:
                                time_slot.status = "active"

                            # 关联到排班结果
                            if schedule_result and not time_slot.schedule_result_id:
                                time_slot.schedule_result_id = schedule_result.id
                                self.logger.debug(
                                    f"关联时间段到排班结果: {schedule_result.id}"
                                )

                            # 添加到待保存列表
                            time_slots_to_add.append(time_slot)
                            time_slots_count += 1

                            # 每500条数据批量保存一次，减少内存占用
                            if len(time_slots_to_add) >= 500:
                                self.logger.info(
                                    f"批量保存 {len(time_slots_to_add)} 个时间段记录"
                                )
                                db.session.bulk_save_objects(time_slots_to_add)
                                time_slots_to_add = []
                        except Exception as e:
                            self.logger.error(f"处理时间段时出错: {str(e)}")
                            continue

                # 保存剩余的时间段记录
                if time_slots_to_add:
                    self.logger.info(
                        f"批量保存剩余的 {len(time_slots_to_add)} 个时间段记录"
                    )
                    db.session.bulk_save_objects(time_slots_to_add)

                # 提交事务由safe_transaction自动处理

            # 记录保存的数据
            self.logger.info("成功保存排班计划:")
            self.logger.info(
                f"  - {len(schedule_results['shift_assignments'])} 个班次分配到shift_assignments表"
            )
            self.logger.info(
                f"  - {schedule_results_count} 个排班结果到schedule_results表"
            )
            self.logger.info(f"  - {time_slots_count} 个时间段分配到time_slots表")
            self.logger.info(
                "重要：护理员可用性数据仅在内存中跟踪，不写入caregiver_schedules表"
            )
            return True
        except Exception as e:
            db.session.rollback()
            self.logger.error(f"保存排班计划失败: {str(e)}")
            return False

    def optimize_with_sa_ga(self, initial_schedule, caregivers):
        """先使用模拟退火算法生成初始解，然后使用遗传算法进一步优化

        这种方法结合了模拟退火算法的全局搜索能力和遗传算法的种群进化机制，
        可以更有效地找到全局最优解。

        Args:
            initial_schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        self.logger.info("开始使用模拟退火算法生成初始解...")

        # 第一步：使用模拟退火算法生成初始解
        sa_solution = self.simulated_annealing_optimize(initial_schedule, caregivers)
        sa_fitness = self.evaluate_schedule(sa_solution, caregivers)
        self.logger.info(f"模拟退火算法生成的初始解适应度: {sa_fitness}")

        # 第二步：使用遗传算法进一步优化
        self.logger.info("开始使用遗传算法进一步优化...")
        ga_solution = self.genetic_algorithm_optimize(sa_solution, caregivers)
        ga_fitness = self.evaluate_schedule(ga_solution, caregivers)
        self.logger.info(f"遗传算法优化后的适应度: {ga_fitness}")

        # 返回最终优化结果
        self.logger.info(f"模拟退火+遗传算法优化完成，最终适应度: {ga_fitness}")
        return ga_solution

    def generate_and_save_schedule(
        self,
        schedule_type=None,
        num_days=None,
        start_date=None,
        shift_start_time=None,
        generate_care_timeline=None,
        shift_mode=None,
        custom_shifts=None,
        time_slots_per_day=None,
        time_interval_minutes=None,
    ):
        """生成并保存排班计划

        Args:
            schedule_type: 排班类型，1(按天), 2(按周), 3(按月), 4(按季度), 5(按年)
            num_days: 排班天数，当schedule_type为1(按天)时有效
            start_date: 开始日期，如果为None则使用全局参数或当前日期
            shift_start_time: 班次开始时间
            generate_care_timeline: 是否生成照护时间线，如果为None，则使用全局参数
            shift_mode: 班制模式，如'one_shift', 'two_shift', 'three_shift', 'custom'
            custom_shifts: 自定义班制模式下的班次列表
            time_slots_per_day: 一天中的时间槽数量，如果为None则使用全局参数
            time_interval_minutes: 每个时间槽的分钟数，如果为None则使用全局参数
        """
        from config_params import three_shift_params

        # 使用全局参数作为默认值
        if schedule_type is None:
            schedule_type = three_shift_params.get("schedule_type", 1)

        if num_days is None:
            num_days = three_shift_params.get("num_days", 1)

        if start_date is None:
            start_date = three_shift_params.get("start_date")

        if shift_start_time is None:
            shift_start_time = three_shift_params.get("shift_start_time", "06:00")

        if generate_care_timeline is None:
            generate_care_timeline = three_shift_params.get(
                "auto_schedule_generate_care_timeline", True
            )

        # 处理时间槽参数
        original_time_slots_per_day = self.time_slots_per_day
        original_time_interval_minutes = self.time_interval_minutes

        # 如果没有提供时间槽参数，尝试从全局参数中获取
        if time_slots_per_day is None and "time_slots_per_day" in three_shift_params:
            time_slots_per_day = three_shift_params["time_slots_per_day"]
            self.logger.info(f"从全局参数中获取时间槽数量: {time_slots_per_day}")

        if (
            time_interval_minutes is None
            and "time_interval_minutes" in three_shift_params
        ):
            time_interval_minutes = three_shift_params["time_interval_minutes"]
            self.logger.info(f"从全局参数中获取时间间隔分钟数: {time_interval_minutes}")

        # 处理时间槽数量参数
        if time_slots_per_day is not None:
            try:
                self.time_slots_per_day = int(time_slots_per_day)
                self.logger.info(f"设置时间槽数量为: {self.time_slots_per_day}")
            except (ValueError, TypeError):
                self.logger.warning(
                    f"无效的时间槽数量: {time_slots_per_day}，使用默认值: {self.time_slots_per_day}"
                )

        # 处理时间间隔分钟数参数
        if time_interval_minutes is not None:
            try:
                self.time_interval_minutes = int(time_interval_minutes)
                self.logger.info(f"设置时间间隔分钟数为: {self.time_interval_minutes}")
            except (ValueError, TypeError):
                self.logger.warning(
                    f"无效的时间间隔分钟数: {time_interval_minutes}，使用默认值: {self.time_interval_minutes}"
                )

        # 检查时间槽参数是否有效
        if self.time_slots_per_day * self.time_interval_minutes != 24 * 60:
            self.logger.warning(
                f"时间槽参数无效: {self.time_slots_per_day} 个时间槽，每个 {self.time_interval_minutes} 分钟，总时间为 {self.time_slots_per_day * self.time_interval_minutes} 分钟，不等于24小时(1440分钟)"
            )

            # 尝试自动调整参数
            if self.time_slots_per_day == 72 and self.time_interval_minutes != 20:
                # 如果时间槽数量是72，则调整时间间隔为20分钟
                self.time_interval_minutes = 20
                self.logger.info("自动调整时间间隔为20分钟，以匹配72个时间槽")
            elif self.time_slots_per_day == 48 and self.time_interval_minutes != 30:
                # 如果时间槽数量是48，则调整时间间隔为30分钟
                self.time_interval_minutes = 30
                self.logger.info("自动调整时间间隔为30分钟，以匹配48个时间槽")
            elif self.time_slots_per_day == 144 and self.time_interval_minutes != 10:
                # 如果时间槽数量是144，则调整时间间隔为10分钟
                self.time_interval_minutes = 10
                self.logger.info("自动调整时间间隔为10分钟，以匹配144个时间槽")
            elif self.time_interval_minutes == 20 and self.time_slots_per_day != 72:
                # 如果时间间隔是20分钟，则调整时间槽数量为72
                self.time_slots_per_day = 72
                self.logger.info("自动调整时间槽数量为72，以匹配20分钟间隔")
            elif self.time_interval_minutes == 30 and self.time_slots_per_day != 48:
                # 如果时间间隔是30分钟，则调整时间槽数量为48
                self.time_slots_per_day = 48
                self.logger.info("自动调整时间槽数量为48，以匹配30分钟间隔")
            elif self.time_interval_minutes == 10 and self.time_slots_per_day != 144:
                # 如果时间间隔是10分钟，则调整时间槽数量为144
                self.time_slots_per_day = 144
                self.logger.info("自动调整时间槽数量为144，以匹配10分钟间隔")
            else:
                # 如果无法自动调整，则恢复为原始参数
                self.logger.info(
                    f"恢复为原始参数: {original_time_slots_per_day} 个时间槽，每个 {original_time_interval_minutes} 分钟"
                )
                self.time_slots_per_day = original_time_slots_per_day
                self.time_interval_minutes = original_time_interval_minutes

        # 处理班制模式参数
        if shift_mode is None:
            # 使用全局参数中的shift_mode
            shift_mode = three_shift_params.get("shift_mode", 3)
            self.logger.info(f"使用全局参数中的班制模式: {shift_mode}")

        # 如果是数字，转换为对应的班制模式字符串
        if isinstance(shift_mode, int) or (
            isinstance(shift_mode, str) and shift_mode.isdigit()
        ):
            shift_number = int(shift_mode)
            if shift_number == 1:
                shift_mode = "one_shift"
                self.logger.info(f"数字班制参数 {shift_number} 映射到一班制")
            elif shift_number == 2:
                shift_mode = "two_shift"
                self.logger.info(f"数字班制参数 {shift_number} 映射到二班制")
            elif shift_number == 3:
                shift_mode = "three_shift"
                self.logger.info(f"数字班制参数 {shift_number} 映射到三班制")
            elif shift_number == 4:
                shift_mode = "custom"
                self.logger.info(f"数字班制参数 {shift_number} 映射到自定义班制")
                # 如果没有提供自定义班次，使用全局参数中的custom_shifts
                if custom_shifts is None:
                    custom_shifts = three_shift_params.get("custom_shifts")
                    self.logger.info(f"使用全局参数中的自定义班次: {custom_shifts}")
            else:
                self.logger.warning(
                    f"无效的数字班制参数: {shift_number}，使用默认的三班制"
                )
                shift_mode = "three_shift"

        # 检查班制模式是否有效
        valid_modes = ["one_shift", "two_shift", "three_shift", "custom"]
        if shift_mode not in valid_modes:
            self.logger.warning(f"无效的班制模式: {shift_mode}，使用默认的三班制")
            shift_mode = "three_shift"

        self.logger.info(f"设置班制模式: {shift_mode}")

        # 如果是自定义模式，需要检查是否提供了自定义班次
        if shift_mode == "custom":
            # 只有在自定义模式下才处理custom_shifts参数
            if custom_shifts is None:
                # 尝试从全局参数中获取自定义班次
                global_custom_shifts = three_shift_params.get("custom_shifts")
                if global_custom_shifts:
                    self.logger.info(
                        f"使用全局参数中的自定义班次: {global_custom_shifts}"
                    )
                    custom_shifts = global_custom_shifts
                else:
                    self.logger.warning(
                        "自定义模式下没有提供班次列表，使用默认的三班制"
                    )
                    shift_mode = "three_shift"
            else:
                self.logger.info(f"自定义模式，使用自定义班次: {custom_shifts}")
        else:
            # 非自定义模式下，忽略custom_shifts参数
            if custom_shifts is not None:
                self.logger.warning(
                    f"在非自定义模式({shift_mode})下提供了custom_shifts参数({custom_shifts})，将被忽略"
                )
                custom_shifts = None

        # 设置班制模式
        if shift_mode is not None or custom_shifts is not None:
            self.set_shift_mode(shift_mode, custom_shifts, shift_start_time)
        elif shift_start_time is not None:
            # 如果只指定了开始时间，使用当前班制模式并更新开始时间
            self.logger.info(
                f"使用当前班制模式 {self.active_mode}，更新班次开始时间: {shift_start_time}"
            )
            self.set_shift_mode(self.active_mode, None, shift_start_time)
        else:
            # 如果没有指定班制模式和开始时间，使用默认的三班制
            default_mode = "three_shift"  # 默认使用三班制
            self.logger.info(
                f"未指定班制模式和开始时间，使用默认班制模式: {default_mode}"
            )
            self.set_shift_mode(default_mode, None, None)

        # 将数字排班类型转换为字符串类型（与原有代码兼容）
        schedule_type_map = {
            1: "daily",
            2: "weekly",
            3: "monthly",
            4: "quarterly",
            5: "yearly",
        }

        # 如果是数字类型，转换为字符串
        if isinstance(schedule_type, int):
            schedule_type_str = schedule_type_map.get(schedule_type)
            if schedule_type_str is None:
                self.logger.warning(
                    f"不支持的排班类型数字: {schedule_type}, 使用默认值'daily'"
                )
                schedule_type_str = "daily"
        else:
            # 如果已经是字符串，直接使用
            schedule_type_str = schedule_type

        self.logger.info(
            f"开始生成排班计划: 类型={schedule_type}({schedule_type_str}), 天数={num_days}, 开始日期={start_date}, 生成照护时间线={generate_care_timeline}"
        )

        # 确保参数类型正确
        try:
            if isinstance(num_days, str):
                num_days = int(num_days)
                self.logger.info(f"将天数从字符串转换为整数: {num_days}")
        except ValueError as e:
            self.logger.warning(f"天数转换失败, 使用默认值1: {str(e)}")
            num_days = 1

        # 生成排班计划
        start_time = datetime.now()
        self.logger.info("开始生成排班计划...")
        schedule_results = self.generate_schedule(
            schedule_type_str, num_days, start_date, shift_start_time
        )
        end_time = datetime.now()
        generation_time = (end_time - start_time).total_seconds()
        self.logger.info(f"排班计划生成完成, 耗时 {generation_time:.2f} 秒")

        # 如果启用了算法优化，使用算法优化排班方案
        # 默认启用算法优化，除非显式禁用
        use_optimization = params.get("use_algorithm_optimization", True)

        # 记录算法参数
        self.logger.info(
            f"算法参数: population_size={self.population_size}, "
            f"crossover_rate={self.crossover_rate}, mutation_rate={self.mutation_rate}, "
            f"phenotype_limit={self.phenotype_limit}, initial_temperature={self.initial_temperature}, "
            f"cooling_rate={self.cooling_rate}"
        )

        if use_optimization:
            # 使用算法优化排班方案
            start_time = datetime.now()
            all_caregivers = self.get_caregivers()

            # 直接使用模拟退火+遗传算法的组合
            self.logger.info("使用模拟退火+遗传算法优化排班方案")
            schedule_results = self.optimize_with_sa_ga(
                schedule_results, all_caregivers
            )

            end_time = datetime.now()
            optimization_time = (end_time - start_time).total_seconds()
            self.logger.info(f"算法优化完成, 耗时 {optimization_time:.2f} 秒")
        else:
            self.logger.info("算法优化已禁用，跳过优化步骤")

        # 保存到数据库
        self.logger.info("开始保存排班计划到数据库...")
        start_time = datetime.now()

        # 根据是否生成照护时间线决定保存的数据
        if not generate_care_timeline:
            # 如果不生成照护时间线，只保存班次分配
            success = self.save_shift_assignments(schedule_results["shift_assignments"])
            self.logger.info("仅保存班次分配，不生成照护时间线")
        else:
            # 如果生成照护时间线，保存所有数据
            success = self.save_schedule(schedule_results, start_date)
            self.logger.info("保存所有数据，包括照护时间线")

        end_time = datetime.now()
        save_time = (end_time - start_time).total_seconds()

        if success:
            self.logger.info(f"排班计划保存成功, 耗时 {save_time:.2f} 秒")
        else:
            self.logger.error(f"排班计划保存失败, 耗时 {save_time:.2f} 秒")

        # 返回结果摘要
        result = {
            "success": success,
            "schedule_type": schedule_type,
            "start_date": (
                start_date.strftime("%Y-%m-%d")
                if isinstance(start_date, date)
                else start_date
            ),
            "shift_assignments_count": len(schedule_results["shift_assignments"]),
            "generate_care_timeline": generate_care_timeline,
            "shift_mode": self.active_mode,
            "shift_mode_name": self.shift_mode_config[self.active_mode]["name"],
            "enabled_shifts": self.shift_control["enabled_shifts"],
            "time_slots_per_day": self.time_slots_per_day,
            "time_interval_minutes": self.time_interval_minutes,
        }

        # 如果生成了照护时间线，添加相关统计信息
        if generate_care_timeline:
            # 计算排班结果数量
            # 注意：每个老人每天应该有一条排班结果记录
            schedule_results_count = 0
            for _, elder_schedule in schedule_results.get(
                "elder_schedules", {}
            ).items():
                # 如果是单个对象
                if "schedule_result" in elder_schedule:
                    schedule_results_count += 1
                # 如果是列表
                elif "schedule_results" in elder_schedule:
                    schedule_results_count += len(elder_schedule["schedule_results"])

            # 计算时间段数量
            time_slots_count = 0
            for elder_schedule in schedule_results.get("elder_schedules", {}).values():
                if "time_slots" in elder_schedule:
                    time_slots_count += len(elder_schedule.get("time_slots", []))

            result.update(
                {
                    "schedule_results_count": schedule_results_count,
                    "time_slots_count": time_slots_count,
                }
            )

        self.logger.info(f"排班结果摘要: {result}")
        return result

    def nsga2_optimize(self, schedule, caregivers):
        """使用NSGA-II多目标优化算法优化排班方案

        Args:
            schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        if not hasattr(self, "nsga2_optimizer"):
            self.logger.warning("NSGA-II优化器未初始化，使用混合算法代替")
            return self.optimize_schedule(schedule, caregivers)

        self.logger.info("开始使用NSGA-II多目标优化算法优化排班方案...")

        # 定义目标函数
        def objective_coverage(schedule):
            return self.evaluate_coverage(schedule)

        def objective_workload_balance(schedule):
            return self.evaluate_workload_balance(schedule, caregivers)

        def objective_preference_satisfaction(schedule):
            return self.evaluate_preference_satisfaction(schedule, caregivers)

        def objective_continuity(schedule):
            return self.evaluate_continuity(schedule)

        # 定义目标函数列表
        objective_functions = [
            objective_coverage,
            objective_workload_balance,
            objective_preference_satisfaction,
            objective_continuity,
        ]

        # 定义创建变异解决方案的函数
        def create_variant_func(solution, _):
            return self.create_schedule_variant(solution, caregivers)

        # 定义交叉函数
        def crossover_func(parent1, parent2):
            return self.crossover(parent1, parent2)

        # 定义变异函数
        def mutate_func(solution, _):
            return self.mutate(solution, caregivers)

        # 使用NSGA-II算法优化
        optimized_schedule = self.nsga2_optimizer.optimize(
            initial_solution=schedule,
            objective_functions=objective_functions,
            create_variant_func=create_variant_func,
            crossover_func=crossover_func,
            mutate_func=mutate_func,
            context=None,
        )

        # 评估最终适应度
        final_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        self.logger.info(f"NSGA-II优化完成，最终适应度: {final_fitness}")

        return optimized_schedule

    def constraint_optimize(self, schedule, caregivers):
        """使用约束满足算法优化排班方案

        Args:
            schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        if not hasattr(self, "constraint_solver"):
            self.logger.warning("约束满足求解器未初始化，使用混合算法代替")
            return self.optimize_schedule(schedule, caregivers)

        self.logger.info("开始使用约束满足算法优化排班方案...")

        # 获取老人列表
        elders = self.get_elders()

        # 获取班次配置
        shift_config = self.current_shift_times

        # 使用约束满足算法优化
        optimized_schedule = self.constraint_solver.solve(
            initial_schedule=schedule,
            caregivers=caregivers,
            elders=elders,
            shift_config=shift_config,
            max_iterations=1000,
        )

        # 评估最终适应度
        final_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        self.logger.info(f"约束满足算法优化完成，最终适应度: {final_fitness}")

        return optimized_schedule

    def rl_optimize(self, schedule, caregivers):
        """使用强化学习算法优化排班方案

        Args:
            schedule: 初始排班方案
            caregivers: 护理员列表

        Returns:
            优化后的排班方案
        """
        if not hasattr(self, "rl_scheduler"):
            self.logger.warning("强化学习调度器未初始化，使用混合算法代替")
            return self.optimize_schedule(schedule, caregivers)

        self.logger.info("开始使用强化学习算法优化排班方案...")

        # 获取历史排班数据
        historical_schedules = self.get_historical_schedules()

        # 获取老人列表
        elders = self.get_elders()

        # 获取班次配置
        shift_config = self.current_shift_times

        # 训练强化学习模型
        if historical_schedules:
            self.logger.info(
                f"使用 {len(historical_schedules)} 条历史排班数据训练强化学习模型"
            )
            self.rl_scheduler.train(
                historical_schedules=historical_schedules,
                caregivers=caregivers,
                elders=elders,
                shift_config=shift_config,
                episodes=500,
            )
        else:
            self.logger.warning("没有历史排班数据，跳过训练阶段")

        # 将排班方案转换为状态
        initial_state = self.rl_scheduler.schedule_to_state(
            schedule, caregivers, elders, shift_config
        )

        # 使用强化学习生成排班方案
        optimized_schedule = self.rl_scheduler.generate_schedule(
            initial_state=initial_state,
            caregivers=caregivers,
            elders=elders,
            shift_config=shift_config,
            max_steps=100,
        )

        # 评估最终适应度
        final_fitness = self.evaluate_schedule(optimized_schedule, caregivers)
        self.logger.info(f"强化学习算法优化完成，最终适应度: {final_fitness}")

        return optimized_schedule

    def get_historical_schedules(self, limit=50):
        """获取历史排班数据

        Args:
            limit: 最大获取数量

        Returns:
            历史排班数据列表
        """
        # 从数据库中获取历史排班数据
        try:
            # 获取最近的排班结果
            schedule_results = (
                ScheduleResult.query.order_by(ScheduleResult.schedule_date.desc())
                .limit(limit)
                .all()
            )

            # 获取对应的班次分配
            historical_schedules = []
            for result in schedule_results:
                # 获取该日期的班次分配
                shift_assignments = ShiftAssignment.query.filter_by(
                    shift_date=result.schedule_date
                ).all()

                # 获取该日期的时间段分配
                time_slots = TimeSlot.query.filter_by(
                    schedule_date=result.schedule_date
                ).all()

                # 构建排班方案
                schedule = {
                    "shift_assignments": shift_assignments,
                    "schedule_results": [result],
                    "time_slots": time_slots,
                    "elder_schedules": {},
                }

                historical_schedules.append(schedule)

            self.logger.info(
                f"从数据库中获取到 {len(historical_schedules)} 条历史排班数据"
            )
            return historical_schedules
        except Exception as e:
            self.logger.error(f"获取历史排班数据失败: {str(e)}")
            return []

    def evaluate_coverage_v2(self, schedule):
        """评估排班方案的班次覆盖率（第二版实现）

        Args:
            schedule: 排班方案

        Returns:
            班次覆盖率评分，越高越好
        """
        # 获取班次分配
        shift_assignments = schedule.get("shift_assignments", [])
        if not shift_assignments:
            return 0

        # 按日期和班次类型分组
        shifts_by_date_type = {}
        for assignment in shift_assignments:
            date_key = str(assignment.shift_date)
            if date_key not in shifts_by_date_type:
                shifts_by_date_type[date_key] = {}

            shift_type = assignment.shift_type
            if shift_type not in shifts_by_date_type[date_key]:
                shifts_by_date_type[date_key][shift_type] = 0

            shifts_by_date_type[date_key][shift_type] += 1

        # 计算班次覆盖率
        total_coverage = 0
        total_days = len(shifts_by_date_type)
        total_shift_types = len(self.current_shift_times)

        if total_days > 0 and total_shift_types > 0:
            for date_key, shifts in shifts_by_date_type.items():
                coverage = len(shifts) / total_shift_types
                total_coverage += coverage

            average_coverage = total_coverage / total_days
            return average_coverage * 100  # 满分100

        return 0

    def evaluate_workload_balance_v2(self, schedule, caregivers):
        """评估排班方案的工作负载平衡性（第二版实现）

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            工作负载平衡性评分，越高越好
        """
        # 获取班次分配
        shift_assignments = schedule.get("shift_assignments", [])
        if not shift_assignments or not caregivers:
            return 0

        # 统计每个护理员的班次数
        caregiver_shifts = {}
        for assignment in shift_assignments:
            caregiver_id = assignment.caregiver_id
            if caregiver_id not in caregiver_shifts:
                caregiver_shifts[caregiver_id] = 0

            caregiver_shifts[caregiver_id] += 1

        # 计算标准差
        if not caregiver_shifts:
            return 0

        shift_counts = list(caregiver_shifts.values())
        mean_shifts = sum(shift_counts) / len(shift_counts)

        if mean_shifts <= 0:
            return 0

        std_dev = (
            sum((count - mean_shifts) ** 2 for count in shift_counts)
            / len(shift_counts)
        ) ** 0.5

        # 标准差越小，平衡度越高，评分越高
        balance_score = 50 / (1 + std_dev)  # 最高分值50
        return balance_score

    def evaluate_preference_satisfaction(self, schedule, caregivers):
        """评估排班方案的护理员偏好满足度

        Args:
            schedule: 排班方案
            caregivers: 护理员列表

        Returns:
            护理员偏好满足度评分，越高越好
        """
        # 获取班次分配
        shift_assignments = schedule.get("shift_assignments", [])
        if not shift_assignments or not caregivers:
            return 0

        # 假设每个护理员有偏好的班次类型
        caregiver_preferences = {}
        for caregiver in caregivers:
            # 随机生成偏好，实际应该从数据库获取
            preferred_shifts = random.sample(
                list(self.current_shift_times.keys()),
                min(2, len(self.current_shift_times)),
            )
            caregiver_preferences[caregiver.id] = preferred_shifts

        # 计算偏好满足度
        total_assignments = len(shift_assignments)
        satisfied_preferences = 0

        for assignment in shift_assignments:
            caregiver_id = assignment.caregiver_id
            shift_type = assignment.shift_type

            if (
                caregiver_id in caregiver_preferences
                and shift_type in caregiver_preferences[caregiver_id]
            ):
                satisfied_preferences += 1

        if total_assignments > 0:
            satisfaction_rate = satisfied_preferences / total_assignments
            return satisfaction_rate * 30  # 最高分值30

        return 0

    def evaluate_continuity_v2(self, schedule):
        """评估排班方案的班次连续性（第二版实现）

        Args:
            schedule: 排班方案

        Returns:
            班次连续性评分，越高越好
        """
        # 获取班次分配
        shift_assignments = schedule.get("shift_assignments", [])
        if not shift_assignments:
            return 0

        # 按护理员和日期分组
        shifts_by_caregiver = {}
        for assignment in shift_assignments:
            caregiver_id = assignment.caregiver_id
            if caregiver_id not in shifts_by_caregiver:
                shifts_by_caregiver[caregiver_id] = {}

            date_key = str(assignment.shift_date)
            if date_key not in shifts_by_caregiver[caregiver_id]:
                shifts_by_caregiver[caregiver_id][date_key] = []

            shifts_by_caregiver[caregiver_id][date_key].append(assignment.shift_type)

        # 计算连续性分数
        continuity_score = 0
        total_caregivers = len(shifts_by_caregiver)

        for caregiver_id, dates in shifts_by_caregiver.items():
            # 按日期排序
            sorted_dates = sorted(dates.keys())

            # 计算连续工作天数
            consecutive_days = 1
            max_consecutive = 1

            for i in range(1, len(sorted_dates)):
                prev_date = datetime.strptime(sorted_dates[i - 1], "%Y-%m-%d").date()
                curr_date = datetime.strptime(sorted_dates[i], "%Y-%m-%d").date()

                if (curr_date - prev_date).days == 1:
                    consecutive_days += 1
                else:
                    consecutive_days = 1

                max_consecutive = max(max_consecutive, consecutive_days)

            # 连续工作3-5天为最佳
            if 3 <= max_consecutive <= 5:
                continuity_score += 1

        if total_caregivers > 0:
            return (continuity_score / total_caregivers) * 20  # 最高分值20

        return 0
